http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / glx / glsnake.c
1 /* glsnake.c - OpenGL imitation of Rubik's Snake
2  * 
3  * (c) 2001-2003 Jamie Wilkinson <jaq@spacepants.org>
4  * (c) 2001-2003 Andrew Bennetts <andrew@puzzling.org> 
5  * (c) 2001-2003 Peter Aylett <peter@ylett.com>
6  * 
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 /* HAVE_GLUT defined if we're building a standalone glsnake,
27  * and not defined if we're building as an xscreensaver hack */
28 #ifdef HAVE_GLUT
29 # include <GL/glut.h>
30 #else
31 # include <GL/gl.h>
32 # include <GL/glu.h>
33 #endif
34
35 #include <stdio.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <libgen.h>
40
41 /* angles */
42 #define ZERO      0.0
43 #define LEFT     90.0
44 #define PIN     180.0
45 #define RIGHT   270.0
46
47 #ifdef HAVE_GETTIMEOFDAY
48 #ifdef GETTIMEOFDAY_TWO_ARGS
49 # include <sys/time.h>
50 # include <time.h>
51   typedef struct timeval snaketime;
52 # define GETSECS(t) ((t).tv_sec)
53 # define GETMSECS(t) ((t).tv_usec/1000)
54 #else /* GETTIMEOFDAY_TWO_ARGS */
55 # include <sys/time.h>
56 # include <time.h>
57   typedef struct timeval snaketime;
58 # define GETSECS(t) ((t).tv_sec)
59 # define GETMSECS(t) ((t).tv_usec/1000)
60 #endif
61 #else /* HAVE_GETTIMEOFDAY */
62 #ifdef HAVE_FTIME
63 # include <sys/timeb.h>
64   typedef struct timeb snaketime;
65 # define GETSECS(t) ((long)(t).time)
66 # define GETMSECS(t) ((t).millitm/1000)
67 #endif /* HAVE_FTIME */
68 #endif /* HAVE_GETTIMEOFDAY */
69
70 #include <math.h>
71
72 #ifndef M_SQRT1_2       /* Win32 doesn't have this constant  */
73 #define M_SQRT1_2 0.70710678118654752440084436210485
74 #endif
75
76 #define NODE_COUNT 24
77
78 #ifdef HAVE_GLUT
79 #define DEF_YANGVEL     0.10
80 #define DEF_ZANGVEL     0.14
81 #define DEF_EXPLODE     0.03
82 #define DEF_ANGVEL      1.0
83 #define DEF_ACCEL       0.1
84 #define DEF_STATICTIME  5000
85 #define DEF_ALTCOLOUR   0
86 #define DEF_TITLES      1
87 #define DEF_INTERACTIVE 0
88 #define DEF_ZOOM        25.0
89 #define DEF_WIREFRAME   0
90 #else
91 /* xscreensaver options doobies prefer strings */
92 #define DEF_YANGVEL     "0.10"
93 #define DEF_ZANGVEL     "0.14"
94 #define DEF_EXPLODE     "0.03"
95 #define DEF_ANGVEL      "1.0"
96 #define DEF_ACCEL       "0.1"
97 #define DEF_STATICTIME  "5000"
98 #define DEF_ALTCOLOUR   "False"
99 #define DEF_TITLES      "True"
100 #define DEF_INTERACTIVE "False"
101 #define DEF_ZOOM        "25.0"
102 #define DEF_WIREFRAME   "False"
103 #endif
104
105 /* static variables */
106 #ifndef HAVE_GLUT
107 # include <X11/Intrinsic.h>
108 #else
109 /* xscreensaver boolean type */
110 # define Bool int
111 #endif
112
113 static GLfloat explode;
114 static GLfloat accel;
115 static long statictime;
116 static GLfloat yspin = 0;
117 static GLfloat zspin = 0;
118 static GLfloat yangvel;
119 static GLfloat zangvel;
120 static Bool altcolour;
121 static Bool titles;
122 static Bool interactive;
123 static Bool wireframe;
124 static GLfloat zoom;
125 static GLfloat angvel;
126
127 #ifndef HAVE_GLUT
128 /* xscreensaver setup */
129 extern XtAppContext app;
130
131 #define PROGCLASS "glsnake"
132 #define HACK_INIT glsnake_init
133 #define HACK_DRAW glsnake_display
134 #define HACK_RESHAPE glsnake_reshape
135 #define sws_opts xlockmore_opts
136
137
138 /* xscreensaver defaults */
139 #define DEFAULTS "*delay:          30000                      \n" \
140                  "*count:          30                         \n" \
141                  "*showFPS:        False                      \n" \
142                  "*wireframe:      False                      \n" \
143                  "*explode:      " DEF_EXPLODE              " \n" \
144                  "*angvel:       " DEF_ANGVEL               " \n" \
145                  "*accel:        " DEF_ACCEL                " \n" \
146                  "*statictime:   " DEF_STATICTIME           " \n" \
147                  "*yangvel:      " DEF_YANGVEL              " \n" \
148                  "*zangvel:      " DEF_ZANGVEL              " \n" \
149                  "*altcolour:    " DEF_ALTCOLOUR            " \n" \
150                  "*titles:         True                       \n" \
151                  "*labelfont:   -*-times-bold-r-normal-*-180-*\n" \
152                  "*zoom:         " DEF_ZOOM                 " \n" \
153
154
155
156 #undef countof
157 #define countof(x) (sizeof((x))/sizeof((*x)))
158
159 #include "xlockmore.h"
160
161 static XrmOptionDescRec opts[] = {
162     { "-explode", ".explode", XrmoptionSepArg, DEF_EXPLODE },
163     { "-angvel", ".angvel", XrmoptionSepArg, DEF_ANGVEL },
164     { "-accel", ".accel", XrmoptionSepArg, DEF_ACCEL },
165     { "-statictime", ".statictime", XrmoptionSepArg, DEF_STATICTIME },
166     { "-yangvel", ".yangvel", XrmoptionSepArg, DEF_YANGVEL },
167     { "-zangvel", ".zangvel", XrmoptionSepArg, DEF_ZANGVEL },
168     { "-altcolour", ".altcolour", XrmoptionNoArg, (caddr_t) "True" },
169     { "-no-altcolour", ".altcolour", XrmoptionNoArg, (caddr_t) "False" },
170     { "-titles", ".titles", XrmoptionNoArg, (caddr_t) "True" },
171     { "-no-titles", ".titles", XrmoptionNoArg, (caddr_t) "False" },
172     { "-zoom", ".zoom", XrmoptionSepArg, DEF_ZOOM },
173     { "-wireframe", ".wireframe", XrmoptionNoArg, (caddr_t) "true" },
174     { "-no-wireframe", ".wireframe", XrmoptionNoArg, (caddr_t) "false" },
175 };
176
177 static argtype vars[] = {
178     {(caddr_t *) &explode, "explode", "Explode", DEF_EXPLODE, t_Float},
179     {(caddr_t *) &angvel, "angvel", "Angular Velocity", DEF_ANGVEL, t_Float},
180     {(caddr_t *) &accel, "accel", "Acceleration", DEF_ACCEL, t_Float},
181     {(caddr_t *) &statictime, "statictime", "Static Time", DEF_STATICTIME, t_Int},
182     {(caddr_t *) &yangvel, "yangvel", "Angular Velocity about Y axis", DEF_YANGVEL, t_Float},
183     {(caddr_t *) &zangvel, "zangvel", "Angular Velocity about X axis", DEF_ZANGVEL, t_Float},
184     {(caddr_t *) &interactive, "interactive", "Interactive", DEF_INTERACTIVE, t_Bool},
185     {(caddr_t *) &altcolour, "altcolour", "Alternate Colour Scheme", DEF_ALTCOLOUR, t_Bool},
186     {(caddr_t *) &titles, "titles", "Titles", DEF_TITLES, t_Bool},
187     {(caddr_t *) &zoom, "zoom", "Zoom", DEF_ZOOM, t_Float},
188     {(caddr_t *) &wireframe, "wireframe", "Wireframe", DEF_WIREFRAME, t_Bool},
189 };
190
191 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
192 #endif
193
194 struct model_s {
195     char * name;
196     float node[NODE_COUNT];
197 };
198
199 struct glsnake_cfg {
200 #ifndef HAVE_GLUT
201     GLXContext * glx_context;
202     XFontStruct * font;
203     GLuint font_list;
204 #else
205     /* font list number */
206     int font;
207 #endif
208
209     /* window id */
210     int window;
211
212     /* is a morph in progress? */
213     int morphing;
214
215     /* has the model been paused? */
216     int paused;
217
218     /* snake metrics */
219     int is_cyclic;
220     int is_legal;
221     int last_turn;
222     int debug;
223
224     /* the shape of the model */
225     float node[NODE_COUNT];
226
227     /* currently selected node for interactive mode */
228     int selected;
229
230     /* models */
231     int prev_model;
232     int next_model;
233
234     /* model morphing */
235     int new_morph;
236
237     /* colours */
238     float colour[2][3];
239     int next_colour;
240     int prev_colour;
241
242     /* timing variables */
243     snaketime last_iteration;
244     snaketime last_morph;
245
246     /* window size */
247     int width, height;
248     int old_width, old_height;
249
250     /* the id of the display lists for drawing a node */
251     int node_solid, node_wire;
252
253     /* is the window fullscreen? */
254     int fullscreen;
255 };
256
257 #define COLOUR_CYCLIC 0
258 #define COLOUR_ACYCLIC 1
259 #define COLOUR_INVALID 2
260 #define COLOUR_AUTHENTIC 3
261
262 float colour[][2][3] = {
263     /* cyclic - green */
264     { { 0.4, 0.8, 0.2 },
265       { 1.0, 1.0, 1.0 } },
266     /* acyclic - blue */
267     { { 0.3, 0.1, 0.9 },
268       { 1.0, 1.0, 1.0 } },
269     /* invalid - grey */
270     { { 0.3, 0.1, 0.9 },
271       { 1.0, 1.0, 1.0 } },
272     /* authentic - purple and green */
273     { { 0.38, 0.0, 0.55 },
274       { 0.0,  0.5, 0.34 } }
275 };
276
277 struct model_s model[] = {
278 #define STRAIGHT_MODEL 0
279     { "straight",
280       { ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO,
281         ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO,
282         ZERO, ZERO }
283     },
284     /* the models in the Rubik's snake manual */
285 #define START_MODEL 1
286     { "ball",
287       { RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT,
288         RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT,
289         RIGHT, LEFT, RIGHT, LEFT }
290     },
291     { "snow",
292       { RIGHT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, RIGHT,
293         RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT,
294         RIGHT, LEFT, LEFT, LEFT }
295     },
296     { "propellor",
297       { ZERO, ZERO, ZERO, RIGHT, LEFT, RIGHT, ZERO, LEFT, ZERO, ZERO,
298         ZERO, RIGHT, LEFT, RIGHT, ZERO, LEFT, ZERO, ZERO, ZERO, RIGHT,
299         LEFT, RIGHT, ZERO, LEFT }
300     },
301     { "flamingo",
302       { ZERO, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, PIN, RIGHT, RIGHT, PIN,
303         RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, RIGHT, ZERO, ZERO,
304         ZERO, PIN }
305     },
306     { "cat",
307       { ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN,
308         ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, ZERO,
309         ZERO }
310     },
311     { "rooster",
312       { ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, LEFT, RIGHT, PIN, RIGHT,
313         ZERO, PIN, PIN, ZERO, RIGHT, PIN, RIGHT, LEFT, ZERO, LEFT, ZERO,
314         PIN }
315     },
316     /* These models were taken from Andrew and Peter's original snake.c
317      * as well as some newer ones made up by Jamie, Andrew and Peter. */
318     { "half balls",
319       { LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT,
320         LEFT, LEFT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT,
321         RIGHT, LEFT, LEFT, LEFT }
322     },
323     { "zigzag1",
324       { RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT,
325         LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT,
326         RIGHT, RIGHT, LEFT, LEFT }
327     },
328     { "zigzag2",
329       { PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN,
330         ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN }
331     },
332     { "zigzag3",
333       { PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN,
334         LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN }
335     },
336     { "caterpillar",
337       { RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT,
338         LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN,
339         LEFT, LEFT }
340     },
341     { "bow",
342       { RIGHT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT,
343         LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT,
344         RIGHT, RIGHT, LEFT, LEFT }
345     },
346     { "turtle",
347       { ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT,
348         LEFT, RIGHT, LEFT, LEFT, PIN, LEFT, LEFT, LEFT, RIGHT, LEFT,
349         RIGHT, RIGHT, RIGHT }
350     },
351     { "basket",
352       { RIGHT, PIN, ZERO, ZERO, PIN, LEFT, ZERO, LEFT, LEFT, ZERO,
353         LEFT, PIN, ZERO, ZERO, PIN, RIGHT, PIN, LEFT, PIN, ZERO, ZERO,
354         PIN, LEFT }
355     },
356     { "thing",
357       { PIN, RIGHT, LEFT, RIGHT, RIGHT, LEFT, PIN, LEFT, RIGHT, LEFT,
358         LEFT, RIGHT, PIN, RIGHT, LEFT, RIGHT, RIGHT, LEFT, PIN, LEFT,
359         RIGHT, LEFT, LEFT }
360     },
361     { "hexagon",
362       { ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, RIGHT, ZERO, ZERO,
363         ZERO, ZERO, LEFT, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO,
364         LEFT, ZERO, ZERO, RIGHT }
365     },
366     { "tri1",
367       { ZERO, ZERO, LEFT, RIGHT, ZERO, LEFT, ZERO, RIGHT, ZERO, ZERO,
368         LEFT, RIGHT, ZERO, LEFT, ZERO, RIGHT, ZERO, ZERO, LEFT, RIGHT,
369         ZERO, LEFT, ZERO, RIGHT }
370     },
371     { "triangle",
372       { ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO,
373         ZERO, ZERO, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, ZERO, ZERO,
374         ZERO, ZERO, LEFT, RIGHT }
375     },
376     { "flower",
377       { ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT,
378         RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, LEFT, PIN,
379         RIGHT, RIGHT, PIN }
380     },
381     { "crucifix",
382       { ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN,
383         PIN, ZERO, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN }
384     },
385     { "kayak",
386       { PIN, RIGHT, LEFT, PIN, LEFT, PIN, ZERO, ZERO, RIGHT, PIN, LEFT,
387         ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO,
388         PIN, RIGHT }
389     },
390     { "bird",
391       { ZERO, ZERO, ZERO, ZERO, RIGHT, RIGHT, ZERO, LEFT, PIN, RIGHT,
392         ZERO, RIGHT, ZERO, RIGHT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT,
393         LEFT, ZERO, PIN }
394     },
395     { "seal",
396       { RIGHT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO,
397         LEFT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, LEFT, LEFT, PIN, RIGHT,
398         RIGHT, LEFT }
399     },
400     { "dog",
401       { ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, PIN,
402         ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN }
403     },
404     { "frog",
405       { RIGHT, RIGHT, LEFT, LEFT, RIGHT, PIN, RIGHT, PIN, LEFT, PIN,
406         RIGHT, ZERO, LEFT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, LEFT,
407         RIGHT, LEFT, LEFT }
408     },
409     { "quavers",
410       { LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, ZERO, ZERO, ZERO,
411         RIGHT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, ZERO, LEFT, LEFT,
412         RIGHT, LEFT, RIGHT, RIGHT }
413     },
414     { "fly",
415       { LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, ZERO, PIN, ZERO, ZERO,
416         LEFT, PIN, RIGHT, ZERO, ZERO, PIN, ZERO, LEFT, LEFT, RIGHT, LEFT,
417         RIGHT, RIGHT }
418     },
419     { "puppy",
420       { ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO,
421         RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT,
422         LEFT }
423     },
424     { "stars",
425       { LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT,
426         ZERO, ZERO, ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN,
427         RIGHT, LEFT }
428     },
429     { "mountains",
430       { RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN,
431         LEFT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT,
432         PIN, LEFT, PIN }
433     },
434     { "quad1",
435       { RIGHT, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, LEFT, LEFT, PIN,
436         LEFT, PIN, RIGHT, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, LEFT,
437         LEFT, PIN, LEFT, PIN }
438     },
439     { "quad2",
440       { ZERO, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, LEFT, LEFT, PIN,
441         ZERO, PIN, ZERO, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, LEFT, LEFT,
442         PIN, ZERO, PIN }
443     },
444     { "glasses",
445       { ZERO, PIN, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO, PIN,
446         ZERO, PIN, ZERO, PIN, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO,
447         PIN, ZERO, PIN }
448     },
449     { "em",
450       { ZERO, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN,
451         ZERO, PIN, ZERO, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO,
452         PIN, ZERO, PIN }
453     },
454     { "quad3",
455       { ZERO, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, LEFT,
456         ZERO, PIN, ZERO, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO,
457         LEFT, ZERO, PIN }
458     },
459     { "vee",
460       { ZERO, ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, ZERO,
461         ZERO, PIN, ZERO, ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO,
462         ZERO, ZERO, PIN }
463     },
464     { "square",
465       { ZERO, ZERO, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO, ZERO,
466         ZERO, PIN, ZERO, ZERO, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO,
467         ZERO, ZERO, PIN }
468     },
469     { "eagle",
470       { RIGHT, ZERO, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO, ZERO,
471         LEFT, PIN, RIGHT, ZERO, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT,
472         ZERO, ZERO, LEFT, PIN }
473     },
474     { "volcano",
475       { RIGHT, ZERO, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT,
476         ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, RIGHT, RIGHT, PIN, LEFT,
477         LEFT, RIGHT, ZERO, LEFT, PIN }
478     },
479     { "saddle",
480       { RIGHT, ZERO, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, ZERO,
481         LEFT, PIN, RIGHT, ZERO, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT,
482         ZERO, LEFT, PIN }
483     },
484     { "c3d",
485       { ZERO, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, LEFT, ZERO,
486         ZERO, PIN, ZERO, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, LEFT,
487         ZERO, ZERO, PIN }
488     },
489     { "block",
490       { ZERO, ZERO, PIN, PIN, ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, PIN,
491         RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, LEFT,
492         PIN, RIGHT }
493     },
494     { "duck",
495       { LEFT, PIN, LEFT, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, LEFT,
496         PIN, RIGHT, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, LEFT, PIN,
497         LEFT }
498     },
499     { "prayer",
500       { RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, ZERO, ZERO,
501         ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, ZERO, RIGHT, RIGHT, LEFT,
502         RIGHT, LEFT, LEFT, LEFT, PIN }
503     },
504     { "giraffe",
505       { ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, ZERO, RIGHT,
506         RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT, RIGHT,
507         PIN, LEFT, LEFT, LEFT }
508     },
509     { "tie fighter",
510       { PIN, LEFT, RIGHT, LEFT, LEFT, PIN, RIGHT, ZERO, RIGHT, LEFT,
511         ZERO, PIN, LEFT, LEFT, RIGHT, RIGHT, RIGHT, PIN, LEFT, ZERO,
512         LEFT, RIGHT, ZERO }
513     },
514     { "Strong Arms",
515       { PIN, PIN, ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, ZERO, RIGHT,
516         RIGHT, PIN, RIGHT, RIGHT, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO,
517         ZERO, PIN, PIN, ZERO }
518     },
519
520     /* the following modesl were created during the slug/compsoc codefest
521      * febrray 2003 */
522     { "cool gegl",
523       { PIN, PIN, ZERO, ZERO, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, LEFT,
524         ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, LEFT, RIGHT, PIN, ZERO,
525         ZERO, ZERO }
526     },
527     { "knuckledusters",
528       { ZERO, ZERO, ZERO, ZERO, PIN, RIGHT, ZERO, PIN, PIN, ZERO, PIN,
529         PIN, ZERO, RIGHT, RIGHT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO,
530         RIGHT, ZERO }
531     },
532     { "k's turd",
533       { RIGHT, RIGHT, PIN, RIGHT, LEFT, RIGHT, PIN, RIGHT, LEFT,
534         RIGHT, PIN, RIGHT, LEFT, RIGHT, PIN, RIGHT, LEFT, RIGHT, PIN,
535         RIGHT, LEFT, RIGHT, PIN, ZERO }
536     },
537     { "lightsabre",
538       { ZERO, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO,
539         ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO,
540         ZERO, ZERO }
541     },
542     { "not a stairway",
543       { LEFT, ZERO, RIGHT, LEFT, RIGHT, ZERO, LEFT, RIGHT, LEFT, ZERO,
544         RIGHT, LEFT, RIGHT, ZERO, LEFT, RIGHT, LEFT, ZERO, RIGHT, LEFT,
545         RIGHT, ZERO, LEFT, ZERO }
546     },
547     { "arse gegl",
548       { ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO,
549         PIN, PIN, ZERO, RIGHT, LEFT, ZERO, PIN, ZERO, PIN, PIN, ZERO,
550         PIN, ZERO }
551     },
552     { "box",
553       { ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, ZERO,
554         ZERO, PIN, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO,
555         ZERO, ZERO, ZERO }
556     },
557     { "kissy box",
558       { PIN, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, ZERO,
559         ZERO, PIN, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO,
560         ZERO, PIN, ZERO }
561     },
562     { "erect penis",     /* thanks benno */
563       { PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, PIN,
564         PIN, ZERO, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO,
565         ZERO, ZERO }
566     },
567     { "flaccid penis",
568       { PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, PIN,
569         PIN, ZERO, ZERO, ZERO, RIGHT, PIN, ZERO, ZERO, ZERO, ZERO, ZERO,
570         ZERO, ZERO }
571     },
572     { "vagina",
573       { RIGHT, ZERO, ZERO, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO,
574         LEFT, ZERO, ZERO, ZERO, LEFT, ZERO, LEFT, PIN, LEFT, PIN, RIGHT,
575         PIN, RIGHT, ZERO }
576     },
577     { "mask",
578       { ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, ZERO, PIN,
579         ZERO, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO,
580         ZERO, ZERO, ZERO }
581     },
582     { "poles or columns or something",
583       { LEFT, RIGHT, LEFT, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO,
584         ZERO, LEFT, RIGHT, LEFT, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO,
585         ZERO, LEFT, ZERO }
586     },
587     { "crooked v",
588       { ZERO, LEFT, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO,
589         ZERO, LEFT, ZERO, LEFT, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO,
590         ZERO, ZERO, ZERO }
591     },
592     { "dog leg",
593       { ZERO, LEFT, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO,
594         LEFT, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO,
595         ZERO, ZERO }
596     },
597     { "scrubby",
598       { ZERO, ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, ZERO, ZERO,
599         LEFT, RIGHT, ZERO, ZERO, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO,
600         LEFT, PIN, ZERO, ZERO }
601     },
602     { "voltron's eyes",
603       { ZERO, ZERO, PIN, RIGHT, ZERO, LEFT, ZERO, ZERO, RIGHT, ZERO,
604         LEFT, PIN, ZERO, ZERO, PIN, ZERO, LEFT, ZERO, RIGHT, LEFT, ZERO,
605         RIGHT, ZERO, ZERO }
606     },
607     { "flying toaster",
608       { PIN, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO,
609         RIGHT, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, ZERO,
610         PIN, ZERO }
611     },
612     { "dubbya",
613       { PIN, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO,
614         ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, ZERO,
615         PIN, ZERO }
616     },
617     { "tap handle",
618       { PIN, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO,
619         LEFT, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, ZERO,
620         PIN, ZERO }
621     },
622     { "wingnut",
623       { PIN, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO,
624         PIN, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, ZERO,
625         PIN, ZERO }
626     },
627     { "tight twist",
628       { RIGHT, ZERO, ZERO, LEFT, ZERO, LEFT, RIGHT, ZERO, RIGHT, LEFT,
629         RIGHT, PIN, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT,
630         ZERO, ZERO, RIGHT, ZERO }
631     },
632     { "double helix",
633       { RIGHT, ZERO, RIGHT, ZERO, RIGHT, ZERO, RIGHT, ZERO, RIGHT,
634         ZERO, RIGHT, ZERO, RIGHT, LEFT, RIGHT, PIN, ZERO, RIGHT, ZERO,
635         RIGHT, ZERO, RIGHT, ZERO, ZERO }
636     },
637
638     /* These models come from the website at 
639      * http://www.geocities.com/stigeide/snake */
640     { "Abstract",
641         { RIGHT, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT, RIGHT, LEFT, PIN, ZERO, ZERO, PIN, LEFT, RIGHT, LEFT, ZERO, PIN, ZERO, RIGHT, LEFT, RIGHT, ZERO }
642     },
643     { "AlanH1",
644         { LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN }
645     },
646     { "AlanH2",
647         { LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT }
648     },
649     { "AlanH3",
650         { LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN }
651     },
652     { "AlanH4",
653         { ZERO, ZERO, PIN, LEFT, RIGHT, LEFT, ZERO, RIGHT, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT, RIGHT, LEFT, ZERO, RIGHT, LEFT, RIGHT, PIN, ZERO, ZERO }
654     },
655     { "Alien",
656         { RIGHT, LEFT, RIGHT, PIN, ZERO, ZERO, PIN, RIGHT, LEFT, RIGHT, ZERO, PIN, PIN, ZERO, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, ZERO, PIN, PIN }
657     },
658     { "Angel",
659         { ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT }
660     },
661     { "AnotherFigure",
662         { LEFT, PIN, RIGHT, ZERO, ZERO, PIN, RIGHT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, PIN, ZERO }
663     },
664     { "Ball",
665         { LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT }
666     },
667     { "Basket",
668         { ZERO, RIGHT, RIGHT, ZERO, RIGHT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, ZERO, LEFT }
669     },
670     { "Beetle",
671         { PIN, LEFT, RIGHT, ZERO, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, ZERO, LEFT, RIGHT, PIN, RIGHT }
672     },
673     { "Bone",
674         { PIN, PIN, LEFT, ZERO, PIN, PIN, ZERO, LEFT, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, RIGHT, PIN, PIN }
675     },
676     { "Bow",
677         { LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT }
678     },
679     { "Bra",
680         { RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT }
681     },
682     { "BronchoSaurian",
683         { ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, PIN }
684     },
685     { "Cactus",
686         { PIN, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, PIN, LEFT, PIN, ZERO, ZERO }
687     },
688     { "Camel",
689         { RIGHT, ZERO, PIN, RIGHT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, ZERO, ZERO, LEFT }
690     },
691     { "Candlestick",
692         { LEFT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, RIGHT }
693     },
694     { "Cat",
695         { ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO }
696     },
697     { "Cave",
698         { RIGHT, ZERO, ZERO, PIN, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, LEFT, PIN, RIGHT, RIGHT, LEFT, PIN, ZERO, ZERO }
699     },
700     { "Chains",
701         { PIN, ZERO, ZERO, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO }
702     },
703     { "Chair",
704         { RIGHT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, LEFT, RIGHT, LEFT, LEFT }
705     },
706     { "Chick",
707         { RIGHT, RIGHT, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, LEFT, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, LEFT, LEFT }
708     },
709     { "Clockwise",
710         { RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT }
711     },
712     { "Cobra",
713         { ZERO, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, LEFT, ZERO, LEFT, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, RIGHT }
714     },
715     { "Cobra2",
716         { LEFT, ZERO, PIN, ZERO, PIN, LEFT, ZERO, PIN, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, PIN, ZERO, RIGHT, PIN, ZERO, PIN, ZERO, RIGHT }
717     },
718     { "Cobra3",
719         { ZERO, LEFT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, ZERO, ZERO, LEFT, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, LEFT }
720     },
721     { "Compact1",
722         { ZERO, ZERO, PIN, ZERO, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, PIN, PIN, ZERO, ZERO, LEFT, PIN }
723     },
724     { "Compact2",
725         { LEFT, PIN, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, ZERO }
726     },
727     { "Compact3",
728         { ZERO, PIN, ZERO, PIN, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN }
729     },
730     { "Compact4",
731         { PIN, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, RIGHT, PIN, LEFT, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, ZERO }
732     },
733     { "Compact5",
734         { LEFT, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, PIN, LEFT }
735     },
736     { "Contact",
737         { PIN, ZERO, ZERO, PIN, LEFT, LEFT, PIN, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, PIN, RIGHT, RIGHT, PIN, ZERO, ZERO, PIN, RIGHT, PIN }
738     },
739     { "Contact2",
740         { RIGHT, PIN, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, PIN, LEFT, PIN, RIGHT, PIN, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, PIN, LEFT }
741     },
742     { "Cook",
743         { ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, RIGHT, LEFT, PIN, LEFT, ZERO, PIN, PIN, ZERO, LEFT, PIN, LEFT, RIGHT, ZERO, RIGHT, ZERO, PIN }
744     },
745     { "Counterclockwise",
746         { LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT }
747     },
748     { "Cradle",
749         { LEFT, LEFT, ZERO, PIN, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, PIN, ZERO, RIGHT, RIGHT, LEFT, LEFT, ZERO, ZERO, RIGHT }
750     },
751     { "Crankshaft",
752         { ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, ZERO, PIN, RIGHT }
753     },
754     { "Cross",
755         { ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN }
756     },
757     { "Cross2",
758         { ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, ZERO, PIN, PIN, ZERO }
759     },
760     { "Cross3",
761         { ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, ZERO, PIN, PIN, ZERO }
762     },
763     { "CrossVersion1",
764         { PIN, ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, PIN, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN }
765     },
766     { "CrossVersion2",
767         { RIGHT, LEFT, PIN, LEFT, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, LEFT, LEFT, PIN, LEFT, RIGHT }
768     },
769     { "Crown",
770         { LEFT, ZERO, PIN, ZERO, RIGHT, ZERO, ZERO, LEFT, ZERO, PIN, ZERO, RIGHT, LEFT, ZERO, PIN, ZERO, RIGHT, ZERO, ZERO, LEFT, ZERO, PIN, ZERO }
771     },
772     { "DNAStrand",
773         { RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT }
774     },
775     { "Diamond",
776         { ZERO, RIGHT, ZERO, ZERO, LEFT, ZERO, ZERO, RIGHT, PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, ZERO, ZERO, LEFT }
777     },
778     { "Dog",
779         { RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, ZERO, LEFT, RIGHT }
780     },
781     { "DogFace",
782         { ZERO, ZERO, PIN, PIN, ZERO, LEFT, LEFT, RIGHT, PIN, ZERO, PIN, PIN, ZERO, PIN, LEFT, RIGHT, RIGHT, ZERO, PIN, PIN, ZERO, ZERO, PIN }
783     },
784     { "DoublePeak",
785         { ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, LEFT, ZERO, PIN, ZERO, RIGHT, RIGHT, LEFT, PIN, LEFT, RIGHT }
786     },
787     { "DoubleRoof",
788         { ZERO, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT }
789     },
790     { "DoubleToboggan",
791         { ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, ZERO, ZERO, PIN }
792     },
793     { "Doubled",
794         { LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, LEFT, ZERO, LEFT, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT }
795     },
796     { "Doubled1",
797         { LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, ZERO, RIGHT, ZERO, RIGHT, ZERO, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT }
798     },
799     { "Doubled2",
800         { LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, LEFT, RIGHT, ZERO, RIGHT, LEFT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT }
801     },
802     { "DumblingSpoon",
803         { PIN, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO }
804     },
805     { "Embrace",
806         { PIN, ZERO, ZERO, PIN, RIGHT, PIN, LEFT, PIN, ZERO, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, ZERO, PIN, RIGHT, PIN, LEFT, PIN, ZERO }
807     },
808     { "EndlessBelt",
809         { ZERO, RIGHT, LEFT, ZERO, ZERO, ZERO, LEFT, RIGHT, ZERO, PIN, RIGHT, LEFT, ZERO, LEFT, RIGHT, LEFT, PIN, LEFT, RIGHT, LEFT, ZERO, LEFT, RIGHT }
810     },
811     { "Entrance",
812         { LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT }
813     },
814     { "Esthetic",
815         { LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT }
816     },
817     { "Explotion",
818         { RIGHT, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT }
819     },
820     { "F-ZeroXCar",
821         { RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT }
822     },
823     { "Face",
824         { ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT }
825     },
826     { "Fantasy",
827         { LEFT, LEFT, RIGHT, PIN, ZERO, RIGHT, ZERO, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, ZERO, LEFT, ZERO, PIN, LEFT, RIGHT, RIGHT, RIGHT, PIN }
828     },
829     { "Fantasy1",
830         { PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, LEFT, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN }
831     },
832     { "FaserGun",
833         { ZERO, ZERO, LEFT, RIGHT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, RIGHT, ZERO, PIN }
834     },
835     { "FelixW",
836         { ZERO, RIGHT, ZERO, PIN, LEFT, ZERO, LEFT, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, LEFT, RIGHT, ZERO, RIGHT, PIN, ZERO, LEFT, ZERO }
837     },
838     { "Flamingo",
839         { ZERO, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, PIN, LEFT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, LEFT, ZERO, ZERO, ZERO, PIN }
840     },
841     { "FlatOnTheTop",
842         { ZERO, PIN, PIN, ZERO, PIN, RIGHT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, PIN }
843     },
844     { "Fly",
845         { ZERO, LEFT, PIN, RIGHT, ZERO, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT }
846     },
847     { "Fountain",
848         { LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, PIN, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, PIN, RIGHT, PIN }
849     },
850     { "Frog",
851         { LEFT, LEFT, RIGHT, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, RIGHT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, RIGHT, LEFT, RIGHT, RIGHT }
852     },
853     { "Frog2",
854         { LEFT, ZERO, LEFT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, RIGHT, ZERO, RIGHT }
855     },
856     { "Furby",
857         { PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, RIGHT, PIN, LEFT, ZERO, PIN, ZERO, ZERO, PIN }
858     },
859     { "Gate",
860         { ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, LEFT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, RIGHT, ZERO, PIN, PIN, ZERO }
861     },
862     { "Ghost",
863         { LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, LEFT, RIGHT }
864     },
865     { "Globus",
866         { RIGHT, LEFT, ZERO, PIN, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, PIN, ZERO, RIGHT, LEFT, ZERO }
867     },
868     { "Grotto",
869         { PIN, PIN, ZERO, LEFT, RIGHT, LEFT, ZERO, PIN, RIGHT, PIN, LEFT, ZERO, ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, PIN, ZERO, RIGHT, LEFT, RIGHT }
870     },
871     { "H",
872         { PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO, PIN, LEFT, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, PIN, PIN, ZERO }
873     },
874     { "HeadOfDevil",
875         { PIN, ZERO, RIGHT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT, ZERO, ZERO }
876     },
877     { "Heart",
878         { RIGHT, ZERO, ZERO, ZERO, PIN, LEFT, PIN, LEFT, RIGHT, RIGHT, ZERO, PIN, ZERO, LEFT, LEFT, RIGHT, PIN, RIGHT, PIN, ZERO, ZERO, ZERO, LEFT }
879     },
880     { "Heart2",
881         { ZERO, PIN, ZERO, ZERO, LEFT, ZERO, LEFT, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, RIGHT, ZERO, RIGHT, ZERO, ZERO, PIN, ZERO }
882     },
883     { "Hexagon",
884         { ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO }
885     },
886     { "HoleInTheMiddle1",
887         { ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, LEFT, RIGHT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT }
888     },
889     { "HoleInTheMiddle2",
890         { ZERO, LEFT, RIGHT, ZERO, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT, RIGHT, ZERO, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT }
891     },
892     { "HouseBoat",
893         { RIGHT, RIGHT, PIN, LEFT, LEFT, LEFT, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, RIGHT, PIN }
894     },
895     { "HouseByHouse",
896         { LEFT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, RIGHT }
897     },
898     { "Infinity",
899         { LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT }
900     },
901     { "Integral",
902         { RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT }
903     },
904     { "Iron",
905         { ZERO, ZERO, ZERO, ZERO, PIN, RIGHT, ZERO, RIGHT, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, ZERO, RIGHT }
906     },
907     { "JustSquares",
908         { RIGHT, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, LEFT, PIN, RIGHT, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, LEFT }
909     },
910     { "Kink",
911         { ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO }
912     },
913     { "Knot",
914         { LEFT, LEFT, PIN, LEFT, ZERO, LEFT, RIGHT, LEFT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, RIGHT, LEFT, RIGHT, ZERO, RIGHT, PIN, RIGHT, RIGHT, LEFT }
915     },
916     { "Leaf",
917         { ZERO, PIN, PIN, ZERO, ZERO, LEFT, ZERO, LEFT, ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO }
918     },
919     { "LeftAsRight",
920         { RIGHT, PIN, LEFT, RIGHT, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, RIGHT, LEFT, RIGHT, PIN, LEFT }
921     },
922     { "Long-necked",
923         { PIN, ZERO, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, PIN, PIN, ZERO }
924     },
925     { "LunaModule",
926         { PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT }
927     },
928     { "MagnifyingGlass",
929         { ZERO, ZERO, PIN, ZERO, LEFT, ZERO, PIN, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, ZERO, ZERO }
930     },
931     { "Mask",
932         { ZERO, ZERO, ZERO, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT }
933     },
934     { "Microscope",
935         { PIN, PIN, ZERO, ZERO, PIN, ZERO, RIGHT, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, LEFT, ZERO, PIN, PIN, ZERO, PIN, PIN }
936     },
937     { "Mirror",
938         { PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, PIN, ZERO, ZERO, LEFT, RIGHT, PIN, RIGHT, ZERO, PIN, PIN, ZERO }
939     },
940     { "MissPiggy",
941         { ZERO, LEFT, LEFT, PIN, RIGHT, ZERO, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, ZERO, LEFT, PIN, RIGHT, RIGHT, ZERO, RIGHT }
942     },
943     { "Mole",
944         { ZERO, RIGHT, ZERO, RIGHT, LEFT, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, LEFT, RIGHT, LEFT, ZERO, LEFT, ZERO, RIGHT, RIGHT, PIN, LEFT }
945     },
946     { "Monk",
947         { LEFT, ZERO, PIN, PIN, ZERO, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT }
948     },
949     { "Mountain",
950         { ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, LEFT, PIN, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO }
951     },
952     { "Mountains",
953         { ZERO, PIN, ZERO, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, ZERO, PIN, ZERO }
954     },
955     { "MouseWithoutTail",
956         { ZERO, PIN, PIN, ZERO, LEFT, ZERO, PIN, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO }
957     },
958     { "Mushroom",
959         { PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, ZERO, LEFT, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, LEFT, ZERO, PIN }
960     },
961     { "Necklace",
962         { ZERO, ZERO, LEFT, ZERO, ZERO, ZERO, LEFT, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, RIGHT, ZERO, ZERO, ZERO, RIGHT, ZERO, ZERO }
963     },
964     { "NestledAgainst",
965         { LEFT, ZERO, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT }
966     },
967     { "NoClue",
968         { ZERO, RIGHT, PIN, LEFT, LEFT, LEFT, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, ZERO, RIGHT, RIGHT, RIGHT, PIN, LEFT, ZERO }
969     },
970     { "Noname",
971         { LEFT, PIN, RIGHT, PIN, RIGHT, ZERO, PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT }
972     },
973     { "Obelisk",
974         { PIN, ZERO, ZERO, ZERO, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, ZERO, ZERO, ZERO }
975     },
976     { "Ostrich",
977         { ZERO, ZERO, PIN, PIN, ZERO, LEFT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, PIN }
978     },
979     { "Ostrich2",
980         { PIN, PIN, ZERO, PIN, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO }
981     },
982     { "PairOfGlasses",
983         { ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, LEFT, ZERO, PIN, ZERO, RIGHT, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO }
984     },
985     { "Parrot",
986         { ZERO, ZERO, ZERO, ZERO, RIGHT, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, RIGHT, ZERO, RIGHT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, LEFT, ZERO, PIN }
987     },
988     { "Penis",
989         { PIN, PIN, RIGHT, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, LEFT, PIN, PIN }
990     },
991     { "PictureCommingSoon",
992         { LEFT, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT, ZERO, RIGHT, RIGHT }
993     },
994     { "Pitti",
995         { LEFT, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, RIGHT }
996     },
997     { "Plait",
998         { LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, LEFT }
999     },
1000     { "Platform",
1001         { RIGHT, PIN, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, LEFT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT }
1002     },
1003     { "PodRacer",
1004         { ZERO, PIN, ZERO, PIN, RIGHT, PIN, ZERO, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, ZERO, LEFT, ZERO, PIN, LEFT }
1005     },
1006     { "Pokemon",
1007         { LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT }
1008     },
1009     { "Prawn",
1010         { RIGHT, PIN, ZERO, PIN, RIGHT, ZERO, PIN, PIN, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, PIN, PIN, ZERO, LEFT, PIN, ZERO, PIN, LEFT }
1011     },
1012     { "Propeller",
1013         { ZERO, ZERO, ZERO, RIGHT, ZERO, LEFT, RIGHT, LEFT, ZERO, ZERO, ZERO, RIGHT, ZERO, LEFT, RIGHT, LEFT, ZERO, ZERO, ZERO, RIGHT, ZERO, LEFT, RIGHT }
1014     },
1015     { "Pyramid",
1016         { ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, RIGHT, LEFT, LEFT, LEFT, PIN, RIGHT, RIGHT, RIGHT, LEFT }
1017     },
1018     { "QuarterbackTiltedAndReadyToHut",
1019         { PIN, ZERO, RIGHT, RIGHT, LEFT, RIGHT, PIN, RIGHT, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT, RIGHT, LEFT, PIN, LEFT, RIGHT, LEFT, LEFT, ZERO, PIN }
1020     },
1021     { "Ra",
1022         { PIN, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, ZERO, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT }
1023     },
1024     { "Rattlesnake",
1025         { LEFT, ZERO, LEFT, ZERO, LEFT, ZERO, LEFT, LEFT, ZERO, LEFT, ZERO, LEFT, ZERO, LEFT, RIGHT, ZERO, PIN, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT }
1026     },
1027     { "Revelation",
1028         { ZERO, ZERO, ZERO, PIN, ZERO, ZERO, PIN, RIGHT, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, LEFT, PIN, ZERO, ZERO, PIN }
1029     },
1030     { "Revolution1",
1031         { LEFT, LEFT, PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT }
1032     },
1033     { "Ribbon",
1034         { RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT }
1035     },
1036     { "Rocket",
1037         { RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, RIGHT, ZERO, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, ZERO, LEFT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT }
1038     },
1039     { "Roofed",
1040         { ZERO, LEFT, PIN, RIGHT, ZERO, PIN, LEFT, ZERO, PIN, ZERO, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, LEFT, ZERO, PIN, ZERO, RIGHT }
1041     },
1042     { "Roofs",
1043         { PIN, PIN, RIGHT, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, LEFT, PIN, PIN }
1044     },
1045     { "RowHouses",
1046         { RIGHT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT }
1047     },
1048     { "Sculpture",
1049         { RIGHT, LEFT, PIN, ZERO, ZERO, ZERO, LEFT, RIGHT, LEFT, PIN, ZERO, ZERO, PIN, LEFT, RIGHT, LEFT, ZERO, ZERO, ZERO, PIN, LEFT, RIGHT, LEFT }
1050     },
1051     { "Seal",
1052         { LEFT, LEFT, LEFT, PIN, RIGHT, RIGHT, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, LEFT }
1053     },
1054     { "Seal2",
1055         { RIGHT, PIN, ZERO, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, PIN, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO }
1056     },
1057     { "Sheep",
1058         { RIGHT, LEFT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, LEFT, LEFT, RIGHT, LEFT }
1059     },
1060     { "Shelter",
1061         { LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, ZERO, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, RIGHT }
1062     },
1063     { "Ship",
1064         { PIN, RIGHT, LEFT, LEFT, LEFT, LEFT, PIN, RIGHT, RIGHT, RIGHT, RIGHT, LEFT, ZERO, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, LEFT, ZERO, PIN, PIN }
1065     },
1066     { "Shpongle",
1067         { LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO }
1068     },
1069     { "Slide",
1070         { LEFT, RIGHT, LEFT, RIGHT, ZERO, LEFT, RIGHT, LEFT, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, RIGHT, LEFT }
1071     },
1072     { "SmallShip",
1073         { ZERO, LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT, RIGHT, ZERO, LEFT, RIGHT, ZERO, LEFT, RIGHT, ZERO, RIGHT, LEFT, ZERO, LEFT, RIGHT, ZERO, LEFT }
1074     },
1075     { "SnakeReadyToStrike",
1076         { LEFT, ZERO, LEFT, ZERO, LEFT, ZERO, LEFT, RIGHT, ZERO, RIGHT, ZERO, RIGHT, ZERO, LEFT, ZERO, ZERO, ZERO, PIN, ZERO, ZERO, ZERO, ZERO, LEFT }
1077     },
1078     { "Snakes14",
1079         { RIGHT, RIGHT, PIN, ZERO, RIGHT, LEFT, RIGHT, ZERO, ZERO, ZERO, RIGHT, PIN, LEFT, PIN, ZERO, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, LEFT, RIGHT }
1080     },
1081     { "Snakes15",
1082         { ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, ZERO, PIN, RIGHT }
1083     },
1084     { "Snakes18",
1085         { PIN, PIN, LEFT, PIN, LEFT, PIN, RIGHT, ZERO, RIGHT, PIN, RIGHT, ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, PIN, PIN, ZERO, ZERO, PIN }
1086     },
1087     { "Snowflake",
1088         { LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, RIGHT }
1089     },
1090     { "Snowman",
1091         { ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO }
1092     },
1093     { "Source",
1094         { PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN }
1095     },
1096     { "Spaceship",
1097         { PIN, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, RIGHT, PIN, PIN }
1098     },
1099     { "Spaceship2",
1100         { PIN, PIN, LEFT, PIN, LEFT, PIN, RIGHT, ZERO, PIN, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, LEFT, LEFT, PIN, PIN }
1101     },
1102     { "Speedboat",
1103         { LEFT, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, LEFT, ZERO, ZERO, PIN, ZERO, ZERO, RIGHT, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, RIGHT }
1104     },
1105     { "Speedboat2",
1106         { PIN, RIGHT, LEFT, LEFT, RIGHT, RIGHT, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, LEFT, LEFT, RIGHT, RIGHT, LEFT, PIN, ZERO, RIGHT, PIN, LEFT }
1107     },
1108     { "Spider",
1109         { RIGHT, RIGHT, ZERO, ZERO, LEFT, RIGHT, LEFT, PIN, ZERO, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, ZERO, PIN, RIGHT, LEFT, RIGHT, ZERO, ZERO, LEFT }
1110     },
1111     { "Spitzbergen",
1112         { PIN, LEFT, ZERO, RIGHT, RIGHT, LEFT, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, ZERO, PIN, RIGHT, LEFT, LEFT, ZERO }
1113     },
1114     { "Square",
1115         { ZERO, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, ZERO, LEFT, LEFT, PIN, RIGHT, RIGHT, ZERO, ZERO }
1116     },
1117     { "SquareHole",
1118         { PIN, ZERO, PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, PIN }
1119     },
1120     { "Stage",
1121         { RIGHT, ZERO, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, LEFT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, ZERO }
1122     },
1123     { "Stairs",
1124         { ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO }
1125     },
1126     { "Stairs2",
1127         { ZERO, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO }
1128     },
1129     { "Straight",
1130         { ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO }
1131     },
1132     { "Swan",
1133         { ZERO, PIN, ZERO, PIN, LEFT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, LEFT, PIN, LEFT, RIGHT }
1134     },
1135     { "Swan2",
1136         { PIN, ZERO, PIN, RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, RIGHT, PIN, ZERO, ZERO, ZERO, ZERO, ZERO, PIN, PIN }
1137     },
1138     { "Swan3",
1139         { PIN, PIN, ZERO, ZERO, ZERO, RIGHT, ZERO, RIGHT, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, ZERO, RIGHT }
1140     },
1141     { "Symbol",
1142         { RIGHT, RIGHT, PIN, ZERO, PIN, PIN, ZERO, PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, ZERO, PIN, PIN, ZERO, PIN, LEFT, LEFT, RIGHT }
1143     },
1144     { "Symmetry",
1145         { RIGHT, ZERO, LEFT, RIGHT, LEFT, ZERO, LEFT, RIGHT, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, LEFT, RIGHT, ZERO, RIGHT, LEFT, RIGHT, ZERO, LEFT }
1146     },
1147     { "Symmetry2",
1148         { ZERO, PIN, LEFT, LEFT, PIN, ZERO, ZERO, LEFT, PIN, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, PIN, LEFT }
1149     },
1150     { "TableFireworks",
1151         { ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, RIGHT, PIN, RIGHT, LEFT, ZERO, RIGHT, PIN }
1152     },
1153     { "Tapering",
1154         { ZERO, ZERO, RIGHT, LEFT, PIN, LEFT, ZERO, PIN, PIN, ZERO, LEFT, PIN, RIGHT, ZERO, PIN, PIN, ZERO, RIGHT, PIN, RIGHT, LEFT, ZERO, ZERO }
1155     },
1156     { "TaperingTurned",
1157         { ZERO, ZERO, RIGHT, LEFT, PIN, LEFT, ZERO, PIN, PIN, ZERO, LEFT, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, RIGHT, PIN, RIGHT, LEFT, ZERO, ZERO }
1158     },
1159     { "TeaLightStick",
1160         { RIGHT, ZERO, PIN, PIN, ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN }
1161     },
1162     { "Tent",
1163         { RIGHT, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, LEFT, RIGHT, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO }
1164     },
1165     { "Terraces",
1166         { RIGHT, LEFT, ZERO, RIGHT, LEFT, PIN, LEFT, LEFT, PIN, LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT, LEFT, RIGHT, PIN, RIGHT, RIGHT, PIN, RIGHT, LEFT }
1167     },
1168     { "Terrier",
1169         { PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO }
1170     },
1171     { "Three-Legged",
1172         { RIGHT, ZERO, LEFT, RIGHT, ZERO, LEFT, PIN, RIGHT, ZERO, RIGHT, ZERO, PIN, ZERO, LEFT, ZERO, LEFT, PIN, RIGHT, ZERO, LEFT, RIGHT, ZERO, LEFT }
1173     },
1174     { "ThreePeaks",
1175         { RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, ZERO, LEFT }
1176     },
1177     { "ToTheFront",
1178         { ZERO, PIN, RIGHT, LEFT, LEFT, LEFT, PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, LEFT, LEFT, PIN, ZERO, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT }
1179     },
1180     { "Top",
1181         { PIN, LEFT, LEFT, PIN, LEFT, ZERO, ZERO, RIGHT, LEFT, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, PIN, RIGHT, PIN, RIGHT, RIGHT, PIN, ZERO }
1182     },
1183     { "Transport",
1184         { PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, ZERO, ZERO }
1185     },
1186     { "Triangle",
1187         { ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, RIGHT, LEFT, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, RIGHT }
1188     },
1189     { "Tripple",
1190         { PIN, ZERO, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, PIN, ZERO, PIN, LEFT, PIN, RIGHT, PIN, ZERO, PIN, LEFT, PIN, LEFT, PIN, RIGHT, PIN }
1191     },
1192     { "Turtle",
1193         { RIGHT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, PIN, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, ZERO, LEFT, RIGHT, ZERO }
1194     },
1195     { "Twins",
1196         { ZERO, PIN, ZERO, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, PIN, ZERO, ZERO, PIN, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, ZERO, PIN, ZERO, ZERO }
1197     },
1198     { "TwoSlants",
1199         { ZERO, PIN, ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO, ZERO, RIGHT, PIN }
1200     },
1201     { "TwoWings",
1202         { PIN, LEFT, ZERO, RIGHT, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, PIN, PIN, ZERO, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, LEFT, ZERO }
1203     },
1204     { "UFO",
1205         { LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, LEFT, PIN, LEFT, LEFT, LEFT, RIGHT, LEFT, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT }
1206     },
1207     { "USSEnterprice",
1208         { LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, LEFT, ZERO, PIN, PIN, ZERO, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, ZERO }
1209     },
1210     { "UpAndDown",
1211         { ZERO, PIN, ZERO, PIN, ZERO, PIN, LEFT, PIN, RIGHT, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, PIN, LEFT, PIN, RIGHT, PIN, ZERO }
1212     },
1213     { "Upright",
1214         { ZERO, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, PIN, ZERO, ZERO, LEFT, PIN, RIGHT, ZERO, ZERO, PIN, RIGHT, RIGHT, LEFT, RIGHT, LEFT, LEFT, ZERO }
1215     },
1216     { "Upside-down",
1217         { PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, RIGHT, RIGHT, LEFT, LEFT, PIN, RIGHT, RIGHT, LEFT, LEFT, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN }
1218     },
1219     { "Valley",
1220         { ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, RIGHT, ZERO, PIN, ZERO, LEFT, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, PIN, LEFT, ZERO }
1221     },
1222     { "Viaduct",
1223         { PIN, RIGHT, PIN, LEFT, PIN, ZERO, ZERO, PIN, RIGHT, ZERO, RIGHT, RIGHT, ZERO, RIGHT, PIN, ZERO, ZERO, PIN, LEFT, PIN, RIGHT, PIN, ZERO }
1224     },
1225     { "View",
1226         { ZERO, RIGHT, PIN, LEFT, PIN, RIGHT, ZERO, ZERO, RIGHT, PIN, LEFT, LEFT, RIGHT, RIGHT, PIN, LEFT, ZERO, ZERO, LEFT, PIN, RIGHT, PIN, LEFT }
1227     },
1228     { "Waterfall",
1229         { LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT, PIN, LEFT, ZERO, RIGHT }
1230     },
1231     { "WindWheel",
1232         { PIN, RIGHT, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, ZERO }
1233     },
1234     { "Window",
1235         { PIN, ZERO, PIN, PIN, ZERO, ZERO, PIN, ZERO, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, ZERO, PIN, PIN, ZERO, ZERO, ZERO, ZERO }
1236     },
1237     { "WindowToTheWorld",
1238         { PIN, LEFT, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO, RIGHT, PIN, LEFT, ZERO, PIN, ZERO, ZERO, PIN, ZERO, ZERO, PIN, ZERO }
1239     },
1240     { "Windshield",
1241         { PIN, PIN, ZERO, RIGHT, PIN, LEFT, LEFT, PIN, RIGHT, ZERO, PIN, ZERO, LEFT, PIN, RIGHT, RIGHT, PIN, LEFT, ZERO, PIN, PIN, ZERO, PIN }
1242     },
1243     { "WingNut",
1244         { ZERO, ZERO, ZERO, ZERO, PIN, RIGHT, RIGHT, RIGHT, PIN, RIGHT, LEFT, PIN, LEFT, RIGHT, PIN, RIGHT, RIGHT, RIGHT, PIN, ZERO, ZERO, ZERO, ZERO }
1245     },
1246     { "Wings2",
1247         { RIGHT, ZERO, PIN, ZERO, LEFT, PIN, RIGHT, PIN, RIGHT, LEFT, RIGHT, RIGHT, LEFT, LEFT, RIGHT, LEFT, PIN, LEFT, PIN, RIGHT, ZERO, PIN, ZERO }
1248     },
1249     { "WithoutName",
1250         { PIN, RIGHT, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN, ZERO, PIN, RIGHT, PIN, LEFT, PIN, ZERO, PIN, RIGHT, RIGHT, PIN, LEFT, LEFT, PIN }
1251     },
1252     { "Wolf",
1253         { ZERO, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, PIN, ZERO, PIN, PIN, ZERO, PIN, ZERO, ZERO, ZERO, PIN, PIN, ZERO, ZERO, ZERO, PIN }
1254     },
1255     { "X",
1256         { LEFT, ZERO, ZERO, PIN, LEFT, RIGHT, RIGHT, PIN, LEFT, RIGHT, ZERO, PIN, PIN, ZERO, LEFT, RIGHT, PIN, LEFT, LEFT, RIGHT, PIN, ZERO, ZERO }
1257     },
1258 };
1259
1260 int models = (sizeof(model) / sizeof(struct model_s));
1261
1262 #define VOFFSET 0.045
1263
1264 #define X_MASK  1
1265 #define Y_MASK  2
1266 #define Z_MASK  4
1267
1268 /* the connecting string that holds the snake together */
1269 #define MAGICAL_RED_STRING 0
1270
1271 #define GETSCALAR(vec,mask) ((vec)==(mask) ? 1 : ((vec)==-(mask) ? -1 : 0 ))
1272
1273 #ifndef MAX
1274 # define MAX(x, y) ((x) > (y) ? (x) : (y))
1275 #endif
1276 #ifndef MIN
1277 # define MIN(x, y) ((x) < (y) ? (x) : (y))
1278 #endif
1279
1280 #define RAND(n) ((random() & 0x7fffffff) % ((long) (n)))
1281 #define RANDSIGN() ((random() & 1) ? 1 : -1)
1282
1283 /* the triangular prism what makes up the basic unit */
1284 float solid_prism_v[][3] = {
1285     /* first corner, bottom left front */
1286     { VOFFSET, VOFFSET, 1.0 },
1287     { VOFFSET, 0.00, 1.0 - VOFFSET },
1288     { 0.00, VOFFSET, 1.0 - VOFFSET },
1289     /* second corner, rear */
1290     { VOFFSET, VOFFSET, 0.00 },
1291     { VOFFSET, 0.00, VOFFSET },
1292     { 0.00, VOFFSET, VOFFSET },
1293     /* third, right front */
1294     { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 1.0 },
1295     { 1.0 - VOFFSET / M_SQRT1_2, 0.0, 1.0 - VOFFSET },
1296     { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, 1.0 - VOFFSET },
1297     /* fourth, right rear */
1298     { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 0.0 },
1299     { 1.0 - VOFFSET / M_SQRT1_2, 0.0, VOFFSET },
1300     { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, VOFFSET },
1301     /* fifth, upper front */
1302     { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 1.0 },
1303     { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, 1.0 - VOFFSET },
1304     { 0.0, 1.0 - VOFFSET / M_SQRT1_2, 1.0 - VOFFSET},
1305     /* sixth, upper rear */
1306     { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 0.0 },
1307     { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, VOFFSET },
1308     { 0.0, 1.0 - VOFFSET / M_SQRT1_2, VOFFSET }};
1309
1310 float solid_prism_n[][3] = {/* corners */
1311     { -VOFFSET, -VOFFSET, VOFFSET },
1312     { VOFFSET, -VOFFSET, VOFFSET },
1313     { -VOFFSET, VOFFSET, VOFFSET },
1314     { -VOFFSET, -VOFFSET, -VOFFSET },
1315     { VOFFSET, -VOFFSET, -VOFFSET },
1316     { -VOFFSET, VOFFSET, -VOFFSET },
1317     /* edges */
1318     { -VOFFSET, 0.0, VOFFSET },
1319     { 0.0, -VOFFSET, VOFFSET },
1320     { VOFFSET, VOFFSET, VOFFSET },
1321     { -VOFFSET, 0.0, -VOFFSET },
1322     { 0.0, -VOFFSET, -VOFFSET },
1323     { VOFFSET, VOFFSET, -VOFFSET },
1324     { -VOFFSET, -VOFFSET, 0.0 },
1325     { VOFFSET, -VOFFSET, 0.0 },
1326     { -VOFFSET, VOFFSET, 0.0 },
1327     /* faces */
1328     { 0.0, 0.0, 1.0 },
1329     { 0.0, -1.0, 0.0 },
1330     { M_SQRT1_2, M_SQRT1_2, 0.0 },
1331     { -1.0, 0.0, 0.0 },
1332     { 0.0, 0.0, -1.0 }};
1333
1334 float wire_prism_v[][3] = {{ 0.0, 0.0, 1.0 },
1335                            { 1.0, 0.0, 1.0 },
1336                            { 0.0, 1.0, 1.0 },
1337                            { 0.0, 0.0, 0.0 },
1338                            { 1.0, 0.0, 0.0 },
1339                            { 0.0, 1.0, 0.0 }};
1340
1341 float wire_prism_n[][3] = {{ 0.0, 0.0, 1.0},
1342                            { 0.0,-1.0, 0.0},
1343                            { M_SQRT1_2, M_SQRT1_2, 0.0},
1344                            {-1.0, 0.0, 0.0},
1345                            { 0.0, 0.0,-1.0}};
1346
1347 static struct glsnake_cfg * glc = NULL;
1348 #ifdef HAVE_GLUT
1349 # define bp glc
1350 #endif
1351
1352 typedef float (*morphFunc)(long);
1353
1354 #ifdef HAVE_GLUT
1355 /* forward definitions for GLUT functions */
1356 void calc_rotation();
1357 inline void ui_mousedrag();
1358 #endif
1359
1360 void gl_init(
1361 #ifndef HAVE_GLUT
1362              ModeInfo * mi
1363 #endif
1364              ) {
1365     float light_pos[][3] = {{0.0, 0.0, 20.0}, {0.0, 20.0, 0.0}};
1366     float light_dir[][3] = {{0.0, 0.0,-20.0}, {0.0,-20.0, 0.0}};
1367
1368     glClearColor(0.0, 0.0, 0.0, 0.0);
1369     glEnable(GL_DEPTH_TEST);
1370     glShadeModel(GL_SMOOTH);
1371     glCullFace(GL_BACK);
1372     glEnable(GL_CULL_FACE);
1373     glEnable(GL_NORMALIZE);
1374
1375     if (!wireframe) {
1376         glColor3f(1.0, 1.0, 1.0);
1377         glLightfv(GL_LIGHT0, GL_POSITION, light_pos[0]);
1378         glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_dir[0]);
1379         glLightfv(GL_LIGHT1, GL_POSITION, light_pos[1]);
1380         glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_dir[1]);
1381         glEnable(GL_LIGHTING);
1382         glEnable(GL_LIGHT0);
1383         glEnable(GL_LIGHT1);
1384         glEnable(GL_COLOR_MATERIAL);
1385     }
1386 }
1387
1388 void gettime(snaketime *t)
1389 {
1390 #ifdef HAVE_GETTIMEOFDAY
1391 #ifdef GETTIMEOFDAY_TWO_ARGS
1392         struct timezone tzp;
1393         gettimeofday(t, &tzp);
1394 #else /* !GETTIMEOFDAY_TWO_ARGS */
1395         gettimeofday(t);
1396 #endif /* !GETTIMEOFDAY_TWO_ARGS */
1397 #else /* !HAVE_GETTIMEOFDAY */
1398 #ifdef HAVE_FTIME
1399         ftime(t);
1400 #endif /* HAVE_FTIME */
1401 #endif /* !HAVE_GETTIMEOFDAY */
1402 }
1403
1404 #ifndef HAVE_GLUT
1405 static void load_font(ModeInfo * mi, char * res, XFontStruct ** fontp, GLuint * dlistp) {
1406     const char * font = get_string_resource(res, "Font");
1407     XFontStruct * f;
1408     Font id;
1409     int first, last;
1410
1411     if (!font)
1412         font = "-*-helvetica-medium-r-*-*-*-120-*";
1413
1414     f = XLoadQueryFont(mi->dpy, font);
1415     if (!f)
1416         f = XLoadQueryFont(mi->dpy, "fixed");
1417
1418     id = f->fid;
1419     first = f->min_char_or_byte2;
1420     last = f->max_char_or_byte2;
1421
1422     clear_gl_error();
1423     *dlistp = glGenLists((GLuint) last + 1);
1424     check_gl_error("glGenLists");
1425     glXUseXFont(id, first, last - first + 1, *dlistp + first);
1426     check_gl_error("glXUseXFont");
1427
1428     *fontp = f;
1429 }
1430 #endif
1431
1432 void start_morph(int model_index, int immediate);
1433
1434 /* wot initialises it */
1435 void glsnake_init(
1436 #ifndef HAVE_GLUT
1437 ModeInfo * mi
1438 #endif
1439 ) {
1440 #ifndef HAVE_GLUT
1441     struct glsnake_cfg * bp;
1442
1443     /* set up the conf struct and glx contexts */
1444     if (!glc) {
1445         glc = (struct glsnake_cfg *) calloc(MI_NUM_SCREENS(mi), sizeof(struct glsnake_cfg));
1446         if (!glc) {
1447             fprintf(stderr, "%s: out of memory\n", progname);
1448             exit(1);
1449         }
1450     }
1451     bp = &glc[MI_SCREEN(mi)];
1452
1453     if ((bp->glx_context = init_GL(mi)) != NULL) {
1454         gl_init(mi);
1455         glsnake_reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1456     }
1457 #else
1458     gl_init();
1459 #endif
1460
1461     /* initialise conf struct */
1462     memset(&bp->node, 0, sizeof(float) * NODE_COUNT);
1463
1464     bp->selected = 11;
1465     bp->is_cyclic = 0;
1466     bp->is_legal = 1;
1467     bp->last_turn = -1;
1468     bp->morphing = 0;
1469     bp->paused = 0;
1470     bp->new_morph = 0;
1471
1472     gettime(&bp->last_iteration);
1473     memcpy(&bp->last_morph, &bp->last_iteration, sizeof(bp->last_morph));
1474
1475     bp->prev_colour = bp->next_colour = COLOUR_ACYCLIC;
1476     bp->next_model = RAND(models);
1477     bp->prev_model = START_MODEL;
1478     start_morph(bp->prev_model, 1);
1479
1480     /* set up a font for the labels */
1481 #ifndef HAVE_GLUT
1482     if (titles)
1483         load_font(mi, "labelfont", &bp->font, &bp->font_list);
1484 #endif
1485     
1486     /* build a solid display list */
1487     glc->node_solid = glGenLists(1);
1488     glNewList(glc->node_solid, GL_COMPILE);
1489     /* corners */
1490     glBegin(GL_TRIANGLES);
1491     glNormal3fv(solid_prism_n[0]);
1492     glVertex3fv(solid_prism_v[0]);
1493     glVertex3fv(solid_prism_v[2]);
1494     glVertex3fv(solid_prism_v[1]);
1495     
1496     glNormal3fv(solid_prism_n[1]);
1497     glVertex3fv(solid_prism_v[6]);
1498     glVertex3fv(solid_prism_v[7]);
1499     glVertex3fv(solid_prism_v[8]);
1500     
1501     glNormal3fv(solid_prism_n[2]);
1502     glVertex3fv(solid_prism_v[12]);
1503     glVertex3fv(solid_prism_v[13]);
1504     glVertex3fv(solid_prism_v[14]);
1505     
1506     glNormal3fv(solid_prism_n[3]);
1507     glVertex3fv(solid_prism_v[3]);
1508     glVertex3fv(solid_prism_v[4]);
1509     glVertex3fv(solid_prism_v[5]);
1510     
1511     glNormal3fv(solid_prism_n[4]);
1512     glVertex3fv(solid_prism_v[9]);
1513     glVertex3fv(solid_prism_v[11]);
1514     glVertex3fv(solid_prism_v[10]);
1515     
1516     glNormal3fv(solid_prism_n[5]);
1517     glVertex3fv(solid_prism_v[16]);
1518     glVertex3fv(solid_prism_v[15]);
1519     glVertex3fv(solid_prism_v[17]);
1520     glEnd();
1521     /* edges */
1522     glBegin(GL_QUADS);
1523     glNormal3fv(solid_prism_n[6]);
1524     glVertex3fv(solid_prism_v[0]);
1525     glVertex3fv(solid_prism_v[12]);
1526     glVertex3fv(solid_prism_v[14]);
1527     glVertex3fv(solid_prism_v[2]);
1528     
1529     glNormal3fv(solid_prism_n[7]);
1530     glVertex3fv(solid_prism_v[0]);
1531     glVertex3fv(solid_prism_v[1]);
1532     glVertex3fv(solid_prism_v[7]);
1533     glVertex3fv(solid_prism_v[6]);
1534     
1535     glNormal3fv(solid_prism_n[8]);
1536     glVertex3fv(solid_prism_v[6]);
1537     glVertex3fv(solid_prism_v[8]);
1538     glVertex3fv(solid_prism_v[13]);
1539     glVertex3fv(solid_prism_v[12]);
1540     
1541     glNormal3fv(solid_prism_n[9]);
1542     glVertex3fv(solid_prism_v[3]);
1543     glVertex3fv(solid_prism_v[5]);
1544     glVertex3fv(solid_prism_v[17]);
1545     glVertex3fv(solid_prism_v[15]);
1546     
1547     glNormal3fv(solid_prism_n[10]);
1548     glVertex3fv(solid_prism_v[3]);
1549     glVertex3fv(solid_prism_v[9]);
1550     glVertex3fv(solid_prism_v[10]);
1551     glVertex3fv(solid_prism_v[4]);
1552     
1553     glNormal3fv(solid_prism_n[11]);
1554     glVertex3fv(solid_prism_v[15]);
1555     glVertex3fv(solid_prism_v[16]);
1556     glVertex3fv(solid_prism_v[11]);
1557     glVertex3fv(solid_prism_v[9]);
1558     
1559     glNormal3fv(solid_prism_n[12]);
1560     glVertex3fv(solid_prism_v[1]);
1561     glVertex3fv(solid_prism_v[2]);
1562     glVertex3fv(solid_prism_v[5]);
1563     glVertex3fv(solid_prism_v[4]);
1564     
1565     glNormal3fv(solid_prism_n[13]);
1566     glVertex3fv(solid_prism_v[8]);
1567     glVertex3fv(solid_prism_v[7]);
1568     glVertex3fv(solid_prism_v[10]);
1569     glVertex3fv(solid_prism_v[11]);
1570     
1571     glNormal3fv(solid_prism_n[14]);
1572     glVertex3fv(solid_prism_v[13]);
1573     glVertex3fv(solid_prism_v[16]);
1574     glVertex3fv(solid_prism_v[17]);
1575     glVertex3fv(solid_prism_v[14]);
1576     glEnd();
1577     
1578     /* faces */
1579     glBegin(GL_TRIANGLES);
1580     glNormal3fv(solid_prism_n[15]);
1581     glVertex3fv(solid_prism_v[0]);
1582     glVertex3fv(solid_prism_v[6]);
1583     glVertex3fv(solid_prism_v[12]);
1584     
1585     glNormal3fv(solid_prism_n[19]);
1586     glVertex3fv(solid_prism_v[3]);
1587     glVertex3fv(solid_prism_v[15]);
1588     glVertex3fv(solid_prism_v[9]);
1589     glEnd();
1590     
1591     glBegin(GL_QUADS);
1592     glNormal3fv(solid_prism_n[16]);
1593     glVertex3fv(solid_prism_v[1]);
1594     glVertex3fv(solid_prism_v[4]);
1595     glVertex3fv(solid_prism_v[10]);
1596     glVertex3fv(solid_prism_v[7]);
1597     
1598     glNormal3fv(solid_prism_n[17]);
1599     glVertex3fv(solid_prism_v[8]);
1600     glVertex3fv(solid_prism_v[11]);
1601     glVertex3fv(solid_prism_v[16]);
1602     glVertex3fv(solid_prism_v[13]);
1603     
1604     glNormal3fv(solid_prism_n[18]);
1605     glVertex3fv(solid_prism_v[2]);
1606     glVertex3fv(solid_prism_v[14]);
1607     glVertex3fv(solid_prism_v[17]);
1608     glVertex3fv(solid_prism_v[5]);
1609     glEnd();
1610     glEndList();
1611     
1612     /* build wire display list */
1613     glc->node_wire = glGenLists(1);
1614     glNewList(glc->node_wire, GL_COMPILE);
1615     glBegin(GL_LINE_STRIP);
1616     glVertex3fv(wire_prism_v[0]);
1617     glVertex3fv(wire_prism_v[1]);
1618     glVertex3fv(wire_prism_v[2]);
1619     glVertex3fv(wire_prism_v[0]);
1620     glVertex3fv(wire_prism_v[3]);
1621     glVertex3fv(wire_prism_v[4]);
1622     glVertex3fv(wire_prism_v[5]);
1623     glVertex3fv(wire_prism_v[3]);
1624     glEnd();
1625     glBegin(GL_LINES);
1626     glVertex3fv(wire_prism_v[1]);
1627     glVertex3fv(wire_prism_v[4]);
1628     glVertex3fv(wire_prism_v[2]);
1629     glVertex3fv(wire_prism_v[5]);
1630     glEnd();
1631     glEndList();
1632     
1633 #ifdef HAVE_GLUT
1634     /* initialise the rotation */
1635     calc_rotation();
1636 #endif
1637 }
1638
1639 void draw_title(
1640 #ifndef HAVE_GLUT
1641                 ModeInfo * mi
1642 #endif
1643                 ) {
1644 #ifndef HAVE_GLUT
1645     struct glsnake_cfg * bp = &glc[MI_SCREEN(mi)];
1646 #endif
1647
1648     /* draw some text */
1649     glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT);
1650     glDisable(GL_LIGHTING);
1651     glDisable(GL_DEPTH_TEST);
1652     glMatrixMode(GL_PROJECTION);
1653     glPushMatrix();
1654     glLoadIdentity();
1655     glMatrixMode(GL_MODELVIEW);
1656     glPushMatrix();
1657     glLoadIdentity();
1658 #ifdef HAVE_GLUT
1659     gluOrtho2D(0, glc->width, 0, glc->height);
1660 #else
1661     gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
1662 #endif
1663     glColor3f(1.0, 1.0, 1.0);
1664     {
1665         char interactstr[] = "interactive";
1666         char * s;
1667         int i = 0;
1668 #ifdef HAVE_GLUT
1669         int w;
1670 #endif
1671         
1672         if (interactive)
1673             s = interactstr;
1674         else
1675             s = model[glc->next_model].name;
1676 #ifdef HAVE_GLUT
1677         w = glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (unsigned char *) s);
1678         glRasterPos2f(glc->width - w - 3, 4);
1679         while (s[i] != '\0')
1680             glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, s[i++]);
1681 #else
1682         glRasterPos2f(10, mi->xgwa.height - 10 - (bp->font->ascent + bp->font->descent));
1683         while (s[i] != '\0')
1684             glCallList(bp->font_list + (int)s[i++]);
1685 #endif
1686     }
1687     glPopMatrix();
1688     glMatrixMode(GL_PROJECTION);
1689     glPopMatrix();
1690     glPopAttrib();
1691 }
1692
1693 /* apply the matrix to the origin and stick it in vec */
1694 void matmult_origin(float rotmat[16], float vec[4]) {
1695 #if 1
1696     vec[0] = 0.5 * rotmat[0] + 0.5 * rotmat[4] + 0.5 * rotmat [8] + 1 * rotmat[12];
1697     vec[1] = 0.5 * rotmat[1] + 0.5 * rotmat[5] + 0.5 * rotmat [9] + 1 * rotmat[13];
1698     vec[2] = 0.5 * rotmat[2] + 0.5 * rotmat[6] + 0.5 * rotmat[10] + 1 * rotmat[14];
1699     vec[3] = 0.5 * rotmat[3] + 0.5 * rotmat[7] + 0.5 * rotmat[11] + 1 * rotmat[15];
1700 #else
1701     vec[0] = 0 * rotmat [0] + 0 * rotmat [1] + 0 * rotmat [2] + 1 * rotmat [3];
1702     vec[1] = 0 * rotmat [4] + 0 * rotmat [5] + 0 * rotmat [6] + 1 * rotmat [7];
1703     vec[2] = 0 * rotmat [8] + 0 * rotmat [9] + 0 * rotmat[10] + 1 * rotmat[11];
1704     vec[3] = 0 * rotmat[12] + 0 * rotmat[13] + 0 * rotmat[14] + 1 * rotmat[15];
1705 #endif
1706     vec[0] /= vec[3];
1707     vec[1] /= vec[3];
1708     vec[2] /= vec[3];
1709     vec[3] = 1.0;
1710 }
1711
1712 /* wot gets called when the winder is resized */
1713 void glsnake_reshape(
1714 #ifndef HAVE_GLUT
1715                      ModeInfo * mi,
1716 #endif
1717                      int w, int h) {
1718     glViewport(0, 0, (GLint) w, (GLint) h);
1719     glMatrixMode(GL_PROJECTION);
1720     glLoadIdentity();
1721     gluPerspective(zoom, w/(GLfloat)h, 0.05, 100.0);
1722     gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1723     glMatrixMode(GL_MODELVIEW);
1724     /*gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);*/
1725     glLoadIdentity();
1726 #ifdef HAVE_GLUT
1727     glc->width = w;
1728     glc->height = h;
1729 #endif
1730 }
1731
1732 /* Returns the new dst_dir for the given src_dir and dst_dir */
1733 int cross_product(int src_dir, int dst_dir) {
1734     return X_MASK*(GETSCALAR(src_dir,Y_MASK) * GETSCALAR(dst_dir,Z_MASK) -
1735                    GETSCALAR(src_dir,Z_MASK) * GETSCALAR(dst_dir,Y_MASK))+ 
1736         Y_MASK*(GETSCALAR(src_dir,Z_MASK) * GETSCALAR(dst_dir,X_MASK) -
1737                 GETSCALAR(src_dir,X_MASK) * GETSCALAR(dst_dir,Z_MASK))+ 
1738         Z_MASK*(GETSCALAR(src_dir,X_MASK) * GETSCALAR(dst_dir,Y_MASK) -
1739                 GETSCALAR(src_dir,Y_MASK) * GETSCALAR(dst_dir,X_MASK));
1740 }
1741
1742 /* calculate orthogonal snake metrics
1743  *  is_legal  = true if model does not pass through itself
1744  *  is_cyclic = true if last node connects back to first node
1745  *  last_turn = for cyclic snakes, specifes what the 24th turn would be
1746  */
1747 void calc_snake_metrics(void) {
1748     int srcDir, dstDir;
1749     int i, x, y, z;
1750     int prevSrcDir = -Y_MASK;
1751     int prevDstDir = Z_MASK;
1752     int grid[25][25][25];
1753     
1754     /* zero the grid */
1755     memset(&grid, 0, sizeof(int) * 25*25*25);
1756     
1757     glc->is_legal = 1;
1758     x = y = z = 12;
1759     
1760     /* trace path of snake - and keep record for is_legal */
1761     for (i = 0; i < NODE_COUNT - 1; i++) {
1762         /*int ang_card;*/ /* cardinal direction of node angle */
1763         /* establish new state vars */
1764         srcDir = -prevDstDir;
1765         x += GETSCALAR(prevDstDir, X_MASK);
1766         y += GETSCALAR(prevDstDir, Y_MASK);
1767         z += GETSCALAR(prevDstDir, Z_MASK);
1768
1769         switch ((int) model[glc->next_model].node[i]) {
1770           case (int) (ZERO):
1771             dstDir = -prevSrcDir;
1772             break;
1773           case (int) (PIN):
1774             dstDir = prevSrcDir;
1775             break;
1776           case (int) (RIGHT):
1777           case (int) (LEFT):
1778             dstDir = cross_product(prevSrcDir, prevDstDir);
1779             if (model[glc->next_model].node[i] == (int) (RIGHT))
1780                 dstDir = -dstDir;
1781             break;
1782           default:
1783             /* Prevent spurious "might be used 
1784              * uninitialised" warnings when compiling
1785              * with -O2 */
1786             dstDir = 0;
1787             break;
1788         }
1789         
1790         if (grid[x][y][z] == 0)
1791             grid[x][y][z] = srcDir + dstDir;
1792         else if (grid[x][y][z] + srcDir + dstDir == 0)
1793             grid[x][y][z] = 8;
1794         else
1795             glc->is_legal = 0;
1796         
1797         prevSrcDir = srcDir;
1798         prevDstDir = dstDir;
1799     }   
1800     
1801     /* determine if the snake is cyclic */
1802     glc->is_cyclic = (dstDir == Y_MASK && x == 12 && y == 11 && z == 12);
1803     
1804     /* determine last_turn */
1805     glc->last_turn = -1;
1806     if (glc->is_cyclic)
1807         switch (srcDir) {
1808           case -Z_MASK: glc->last_turn = ZERO; break;
1809           case Z_MASK:  glc->last_turn = PIN; break;
1810           case X_MASK:  glc->last_turn = LEFT; break;
1811           case -X_MASK: glc->last_turn = RIGHT; break;
1812         }
1813 }
1814
1815 /* work out how far through the current morph we are */
1816 float morph_percent(void) {
1817     float retval;
1818     int i;
1819
1820     /* extend this function later with a case statement for each of the
1821      * morph schemes */
1822
1823     /* when morphing all nodes at once, the longest morph will be the node
1824      * that needs to rotate 180 degrees.  For each node, work out how far it
1825      * has to go, and store the maximum rotation and current largest angular
1826      * difference, returning the angular difference over the maximum. */
1827     {
1828         float rot_max = 0.0, ang_diff_max = 0.0;
1829
1830         for (i = 0; i < NODE_COUNT - 1; i++) {
1831             float rot, ang_diff;
1832
1833             /* work out the maximum rotation this node has to go through
1834              * from the previous to the next model, taking into account that
1835              * the snake always morphs through the smaller angle */
1836             rot = fabs(model[glc->prev_model].node[i] -
1837                        model[glc->next_model].node[i]);
1838             if (rot > 180.0) rot = 180.0 - rot;
1839             /* work out the difference between the current position and the
1840              * target */
1841             ang_diff = fabs(glc->node[i] -
1842                             model[glc->next_model].node[i]);
1843             if (ang_diff > 180.0) ang_diff = 180 - ang_diff;
1844             /* if it's the biggest so far, record it */
1845             if (rot > rot_max) rot_max = rot;
1846             if (ang_diff > ang_diff_max) ang_diff_max = ang_diff;
1847         }
1848         
1849         /* ang_diff / rot approaches 0, we want the complement */
1850         retval = 1.0 - (ang_diff_max / rot_max);
1851         /* protect against naan */
1852         if (isnan(retval) || isinf(retval)) retval = 1.0;
1853     }
1854     /*printf("morph_pct = %f\n", retval);*/
1855     return retval;
1856 }
1857
1858 void morph_colour(void) {
1859     float percent, compct; /* complement of percentage */
1860
1861     percent = morph_percent();
1862     compct = 1.0 - percent;
1863
1864     glc->colour[0][0] = colour[glc->prev_colour][0][0] * compct + colour[glc->next_colour][0][0] * percent;
1865     glc->colour[0][1] = colour[glc->prev_colour][0][1] * compct + colour[glc->next_colour][0][1] * percent;
1866     glc->colour[0][2] = colour[glc->prev_colour][0][2] * compct + colour[glc->next_colour][0][2] * percent;
1867
1868     glc->colour[1][0] = colour[glc->prev_colour][1][0] * compct + colour[glc->next_colour][1][0] * percent;
1869     glc->colour[1][1] = colour[glc->prev_colour][1][1] * compct + colour[glc->next_colour][1][1] * percent;
1870     glc->colour[1][2] = colour[glc->prev_colour][1][2] * compct + colour[glc->next_colour][1][2] * percent;
1871 }
1872
1873 /* Start morph process to this model */
1874 void start_morph(int model_index, int immediate) {
1875     /* if immediate, don't bother morphing, go straight to the next model */
1876     if (immediate) {
1877         int i;
1878
1879         for (i = 0; i < NODE_COUNT; i++)
1880             glc->node[i] = model[model_index].node[i];
1881     }
1882
1883     glc->prev_model = glc->next_model;
1884     glc->next_model = model_index;
1885     glc->prev_colour = glc->next_colour;
1886
1887     calc_snake_metrics();
1888     if (!glc->is_legal)
1889         glc->next_colour = COLOUR_INVALID;
1890     else if (altcolour)
1891         glc->next_colour = COLOUR_AUTHENTIC;
1892     else if (glc->is_cyclic)
1893         glc->next_colour = COLOUR_CYCLIC;
1894     else
1895         glc->next_colour = COLOUR_ACYCLIC;
1896
1897     if (immediate) {
1898         glc->colour[0][0] = colour[glc->next_colour][0][0];
1899         glc->colour[0][1] = colour[glc->next_colour][0][1];
1900         glc->colour[0][2] = colour[glc->next_colour][0][2];
1901         glc->colour[1][0] = colour[glc->next_colour][1][0];
1902         glc->colour[1][1] = colour[glc->next_colour][1][1];
1903         glc->colour[1][2] = colour[glc->next_colour][1][2];
1904     }
1905     glc->morphing = 1;
1906
1907     morph_colour();
1908 }
1909
1910 /* Returns morph progress */
1911 float morph(long iter_msec) {
1912     /* work out the maximum angle for this iteration */
1913     int still_morphing;
1914     float iter_angle_max, largest_diff, largest_progress;
1915     int i;
1916
1917     if (glc->new_morph)
1918         glc->new_morph = 0;
1919         
1920     iter_angle_max = 90.0 * (angvel/1000.0) * iter_msec;
1921         
1922     still_morphing = 0;
1923     largest_diff = largest_progress = 0.0;
1924     for (i = 0; i < NODE_COUNT; i++) {
1925         float curAngle = glc->node[i];
1926         float destAngle = model[glc->next_model].node[i];
1927         if (curAngle != destAngle) {
1928             still_morphing = 1;
1929             if (fabs(curAngle-destAngle) <= iter_angle_max)
1930                 glc->node[i] = destAngle;
1931             else if (fmod(curAngle-destAngle+360,360) > 180)
1932                 glc->node[i] = fmod(curAngle + iter_angle_max, 360);
1933             else
1934                 glc->node[i] = fmod(curAngle+360 - iter_angle_max, 360);
1935             largest_diff = MAX(largest_diff, fabs(destAngle-glc->node[i]));
1936             largest_progress = MAX(largest_diff, fabs(glc->node[i] - model[glc->prev_model].node[i]));
1937         }
1938     }
1939         
1940     return MIN(largest_diff / largest_progress, 1.0);
1941 }
1942
1943 #ifdef HAVE_GLUT
1944 void glsnake_idle();
1945
1946 void restore_idle(int value)
1947 {
1948     glutIdleFunc(glsnake_idle);
1949 }
1950 #endif
1951
1952 void quick_sleep(void)
1953 {
1954 #ifdef HAVE_GLUT
1955     /* By using glutTimerFunc we can keep responding to 
1956      * mouse and keyboard events, unlike using something like
1957      * usleep. */
1958     glutIdleFunc(NULL);
1959     glutTimerFunc(1, restore_idle, 0);
1960 #else
1961     usleep(1);
1962 #endif
1963 }
1964
1965 void glsnake_idle(
1966 #ifndef HAVE_GLUT
1967                   struct glsnake_cfg * bp
1968 #endif
1969                   ) {
1970     /* time since last iteration */
1971     long iter_msec;
1972     /* time since the beginning of last morph */
1973     long morf_msec;
1974     float iter_angle_max;
1975     snaketime current_time;
1976     /*    morphFunc transition; */
1977     int still_morphing;
1978     int i;
1979     
1980     /* Do nothing to the model if we are paused */
1981     if (glc->paused) {
1982         /* Avoid busy waiting when nothing is changing */
1983         quick_sleep();
1984 #ifdef HAVE_GLUT
1985         glutSwapBuffers();
1986         glutPostRedisplay();
1987 #endif
1988         return;
1989     }
1990
1991     /* <spiv> Well, ftime gives time with millisecond resolution.
1992      * <spiv> (or worse, perhaps... who knows what the OS will do)
1993      * <spiv> So if no discernable amount of time has passed:
1994      * <spiv>   a) There's no point updating the screen, because
1995      *             it would be the same
1996      * <spiv>   b) The code will divide by zero
1997      */
1998     gettime(&current_time);
1999     
2000     iter_msec = (long) GETMSECS(current_time) - GETMSECS(glc->last_iteration) + 
2001         ((long) GETSECS(current_time) - GETSECS(glc->last_iteration)) * 1000L;
2002
2003     if (iter_msec) {
2004         /* save the current time */
2005         memcpy(&glc->last_iteration, &current_time, sizeof(snaketime));
2006         
2007         /* work out if we have to switch models */
2008         morf_msec = GETMSECS(glc->last_iteration) - GETMSECS(glc->last_morph) +
2009             ((long) (GETSECS(glc->last_iteration)-GETSECS(glc->last_morph)) * 1000L);
2010
2011         if ((morf_msec > statictime) && !interactive && !glc->morphing) {
2012             /*printf("starting morph\n");*/
2013             memcpy(&glc->last_morph, &(glc->last_iteration), sizeof(glc->last_morph));
2014             start_morph(RAND(models), 0);
2015         }
2016         
2017         if (interactive && !glc->morphing) {
2018             quick_sleep();
2019             return;
2020         }
2021         
2022         /*      if (!glc->dragging && !glc->interactive) { */
2023         if (!interactive) {
2024             
2025             yspin += 360/((1000/yangvel)/iter_msec);
2026             zspin += 360/((1000/zangvel)/iter_msec);
2027             /*
2028             yspin += 360 * (yangvel/1000.0) * iter_msec;
2029             zspin += 360 * (zangvel/1000.0) * iter_msec;
2030             */
2031             
2032             /*printf("yspin: %f, zspin: %f\n", yspin, zspin);*/
2033
2034         }
2035
2036         /* work out the maximum angle we could turn this node in this
2037          * timeslice, iter_msec milliseconds long */
2038         iter_angle_max = 90.0 * (angvel/1000.0) * iter_msec;
2039
2040         still_morphing = 0;
2041         for (i = 0; i < NODE_COUNT; i++) {
2042             float cur_angle = glc->node[i];
2043             float dest_angle = model[glc->next_model].node[i];
2044             if (cur_angle != dest_angle) {
2045                 still_morphing = 1;
2046                 if (fabs(cur_angle - dest_angle) <= iter_angle_max)
2047                     glc->node[i] = dest_angle;
2048                 else if (fmod(cur_angle - dest_angle + 360, 360) > 180)
2049                     glc->node[i] = fmod(cur_angle + iter_angle_max, 360);
2050                 else
2051                     glc->node[i] = fmod(cur_angle + 360 - iter_angle_max, 360);
2052             }
2053         }
2054
2055         if (!still_morphing)
2056             glc->morphing = 0;
2057
2058         /* colour cycling */
2059         morph_colour();
2060         
2061 #ifdef HAVE_GLUT
2062         glutSwapBuffers();
2063         glutPostRedisplay();
2064 #endif
2065     } else {
2066         /* We are going too fast, so we may as well let the 
2067          * cpu relax a little by sleeping for a millisecond. */
2068         quick_sleep();
2069     }
2070 }
2071
2072 /* wot draws it */
2073 void glsnake_display(
2074 #ifndef HAVE_GLUT
2075                      ModeInfo * mi
2076 #endif
2077                      ) {
2078 #ifndef HAVE_GLUT
2079     struct glsnake_cfg * bp = &glc[MI_SCREEN(mi)];
2080     Display * dpy = MI_DISPLAY(mi);
2081     Window window = MI_WINDOW(mi);
2082 #endif
2083
2084     int i;
2085     float ang;
2086     float positions[NODE_COUNT][4]; /* origin points for each node */
2087     float com[4]; /* it's the CENTRE of MASS */
2088
2089 #ifndef HAVE_GLUT
2090     if (!bp->glx_context)
2091         return;
2092 #endif
2093     
2094     /* clear the buffer */
2095     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2096     
2097     /* go into the modelview stack */
2098     glMatrixMode(GL_MODELVIEW);
2099     glLoadIdentity();
2100     
2101     /* get the centre of each node, by moving through the snake and
2102      * performing the rotations, then grabbing the matrix at each point
2103      * and applying it to the origin */
2104     glPushMatrix();
2105
2106 #ifdef HAVE_GLUT
2107     /* apply the mouse drag rotation */
2108     ui_mousedrag();
2109 #endif
2110     
2111     /* apply the continuous rotation */
2112     glRotatef(yspin, 0.0, 1.0, 0.0); 
2113     glRotatef(zspin, 0.0, 0.0, 1.0); 
2114     
2115     com[0] = 0.0;
2116     com[1] = 0.0;
2117     com[2] = 0.0;
2118     com[3] = 0.0;
2119     for (i = 0; i < NODE_COUNT; i++) {
2120         float rotmat[16];
2121
2122         ang = glc->node[i];
2123
2124         /*printf("ang = %f\n", ang);*/
2125         
2126         glTranslatef(0.5, 0.5, 0.5);            /* move to center */
2127         glRotatef(90, 0.0, 0.0, -1.0);          /* reorient  */
2128         glTranslatef(1.0 + explode, 0.0, 0.0);  /* move to new pos. */
2129         glRotatef(180 + ang, 1.0, 0.0, 0.0);    /* pivot to new angle */
2130         glTranslatef(-0.5, -0.5, -0.5);         /* return from center */
2131
2132         glGetFloatv(GL_MODELVIEW_MATRIX, rotmat);
2133
2134         matmult_origin(rotmat, positions[i]);
2135
2136         /*printf("positions %f %f %f %f\n", positions[i][0], positions[i][1], positions[i][2], positions[i][3]);*/
2137
2138         com[0] += positions[i][0];
2139         com[1] += positions[i][1];
2140         com[2] += positions[i][2];
2141         com[3] += positions[i][3];
2142     }
2143     glPopMatrix();
2144     com[0] /= NODE_COUNT;
2145     com[1] /= NODE_COUNT;
2146     com[2] /= NODE_COUNT;
2147     com[3] /= NODE_COUNT;
2148
2149     com[0] /= com[3];
2150     com[1] /= com[3];
2151     com[2] /= com[3];
2152
2153     /*printf("com: %f, %f, %f, %f\n", com[0], com[1], com[2], com[3]);*/
2154
2155 #if MAGICAL_RED_STRING
2156     glPushMatrix();
2157     glTranslatef(-com[0], -com[1], -com[2]);
2158
2159     glDisable(GL_LIGHTING);
2160     glColor3f(1.0, 0.0, 0.0);
2161     glBegin(GL_LINE_STRIP);
2162     for (i = 0; i < NODE_COUNT - 1; i++) {
2163         glVertex3fv(positions[i]);
2164     }
2165     glEnd();
2166     glEnable(GL_LIGHTING);
2167     /*glTranslatef(com[0], com[1], com[2]);*/
2168     glPopMatrix();
2169 #endif
2170
2171     glPushMatrix();
2172     glTranslatef(-com[0], -com[1], -com[2]);
2173
2174 #ifdef HAVE_GLUT
2175     /* apply the mouse drag rotation */
2176     ui_mousedrag();
2177 #endif
2178     
2179     /* apply the continuous rotation */
2180     glRotatef(yspin, 0.0, 1.0, 0.0); 
2181     glRotatef(zspin, 0.0, 0.0, 1.0); 
2182
2183     /* now draw each node along the snake -- this is quite ugly :p */
2184     for (i = 0; i < NODE_COUNT; i++) {
2185         /* choose a colour for this node */
2186         if ((i == glc->selected || i == glc->selected+1) && interactive)
2187             /* yellow */
2188             glColor3f(1.0, 1.0, 0.0);
2189         else
2190             glColor3fv(glc->colour[(i+1)%2]);
2191
2192         /* draw the node */
2193         if (wireframe)
2194             glCallList(glc->node_wire);
2195         else
2196             glCallList(glc->node_solid);
2197
2198         /* now work out where to draw the next one */
2199         
2200         /* Interpolate between models */
2201         ang = glc->node[i];
2202         
2203         glTranslatef(0.5, 0.5, 0.5);            /* move to center */
2204         glRotatef(90, 0.0, 0.0, -1.0);          /* reorient  */
2205         glTranslatef(1.0 + explode, 0.0, 0.0);  /* move to new pos. */
2206         glRotatef(180 + ang, 1.0, 0.0, 0.0);    /* pivot to new angle */
2207         glTranslatef(-0.5, -0.5, -0.5);         /* return from center */
2208     }
2209
2210     glPopMatrix();
2211     
2212     if (titles)
2213 #ifdef HAVE_GLUT
2214         draw_title();
2215 #else
2216         draw_title(mi);
2217 #endif
2218
2219 #ifndef HAVE_GLUT
2220         glsnake_idle(bp);
2221 #endif
2222     
2223     glFlush();
2224 #ifdef HAVE_GLUT
2225     glutSwapBuffers();
2226 #else
2227     glXSwapBuffers(dpy, window);
2228 #endif
2229 }
2230
2231 #ifdef HAVE_GLUT
2232 /* anything that needs to be cleaned up goes here */
2233 void unmain() {
2234     glutDestroyWindow(glc->window);
2235     free(glc);
2236 }
2237
2238 void ui_init(int *, char **);
2239
2240 int main(int argc, char ** argv) {
2241     glc = malloc(sizeof(struct glsnake_cfg));
2242     memset(glc, 0, sizeof(struct glsnake_cfg));
2243
2244     glc->width = 320;
2245     glc->height = 240;
2246     
2247     ui_init(&argc, argv);
2248
2249     gettime(&glc->last_iteration);
2250     memcpy(&glc->last_morph, &glc->last_iteration, sizeof(snaketime));
2251     srand((unsigned int)GETSECS(glc->last_iteration));
2252
2253     glc->prev_colour = glc->next_colour = COLOUR_ACYCLIC;
2254     glc->next_model = RAND(models);
2255     glc->prev_model = 0;
2256     start_morph(glc->prev_model, 1);    
2257
2258     glsnake_init();
2259     
2260     atexit(unmain);
2261     glutSwapBuffers();
2262     glutMainLoop();
2263     
2264     return 0;
2265 }
2266 #endif
2267
2268 /*
2269  * GLUT FUNCTIONS
2270  */
2271
2272 #ifdef HAVE_GLUT
2273
2274 /* trackball quaternions */
2275 float cumquat[4] = {0.0,0.0,0.0,0.0}, oldquat[4] = {0.0,0.0,0.0,0.1};
2276
2277 /* rotation matrix */
2278 float rotation[16];
2279
2280 /* mouse drag vectors: start and end */
2281 float m_s[3], m_e[3];
2282
2283 /* dragging boolean */
2284 int dragging = 0;
2285
2286 /* this function calculates the rotation matrix based on the quaternions
2287  * generated from the mouse drag vectors */
2288 void calc_rotation() {
2289     double Nq, s;
2290     double xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
2291
2292     /* this bit ripped from Shoemake's quaternion notes from SIGGRAPH */
2293     Nq = cumquat[0] * cumquat[0] + cumquat[1] * cumquat[1] +
2294         cumquat[2] * cumquat[2] + cumquat[3] * cumquat[3];
2295     s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
2296     xs = cumquat[0] *  s; ys = cumquat[1] *  s; zs = cumquat[2] * s;
2297     wx = cumquat[3] * xs; wy = cumquat[3] * ys; wz = cumquat[3] * zs;
2298     xx = cumquat[0] * xs; xy = cumquat[0] * ys; xz = cumquat[0] * zs;
2299     yy = cumquat[1] * ys; yz = cumquat[1] * zs; zz = cumquat[2] * zs;
2300
2301     rotation[0] = 1.0 - (yy + zz);
2302     rotation[1] = xy + wz;
2303     rotation[2] = xz - wy;
2304     rotation[4] = xy - wz;
2305     rotation[5] = 1.0 - (xx + zz);
2306     rotation[6] = yz + wx;
2307     rotation[8] = xz + wy;
2308     rotation[9] = yz - wx;
2309     rotation[10] = 1.0 - (xx + yy);
2310     rotation[3] = rotation[7] = rotation[11] = 0.0;
2311     rotation[12] = rotation[13] = rotation[14] = 0.0;
2312     rotation[15] = 1.0;
2313 }
2314
2315 inline void ui_mousedrag() {
2316     glMultMatrixf(rotation);
2317 }
2318
2319 void ui_keyboard(unsigned char c, int x, int y) {
2320     int i;
2321     
2322     switch (c) {
2323       case 27:  /* ESC */
2324       case 'q':
2325         exit(0);
2326         break;
2327       case 'e':
2328         explode += DEF_EXPLODE;
2329         glutPostRedisplay();
2330         break;
2331       case 'E':
2332         explode -= DEF_EXPLODE;
2333         if (explode < 0.0) explode = 0.0;
2334         glutPostRedisplay();
2335         break;
2336       case '.':
2337         /* next model */
2338         glc->next_model++;
2339         glc->next_model %= models;
2340         start_morph(glc->next_model, 0);
2341         
2342         /* Reset last_morph time */
2343         gettime(&glc->last_morph);                      
2344         break;
2345       case ',':
2346         /* previous model */
2347         glc->next_model = (glc->next_model + models - 1) % models;
2348         start_morph(glc->next_model, 0);
2349         
2350         /* Reset glc->last_morph time */
2351         gettime(&glc->last_morph);                      
2352         break;
2353       case '+':
2354         angvel += DEF_ACCEL;
2355         break;
2356       case '-':
2357         if (angvel > DEF_ACCEL)
2358             angvel -= DEF_ACCEL;
2359         break;
2360       case 'i':
2361         if (interactive) {
2362             /* Reset last_iteration and last_morph time */
2363             gettime(&glc->last_iteration);
2364             gettime(&glc->last_morph);
2365         }
2366         interactive = 1 - interactive;
2367         glutPostRedisplay();
2368         break;
2369       case 'w':
2370         wireframe = 1 - wireframe;
2371         if (wireframe)
2372             glDisable(GL_LIGHTING);
2373         else
2374             glEnable(GL_LIGHTING);
2375         glutPostRedisplay();
2376         break;
2377       case 'p':
2378         if (glc->paused) {
2379             /* unpausing, reset last_iteration and last_morph time */
2380             gettime(&glc->last_iteration);
2381             gettime(&glc->last_morph);
2382         }
2383         glc->paused = 1 - glc->paused;
2384         break;
2385       case 'd':
2386         /* dump the current model so we can add it! */
2387         printf("# %s\nnoname:\t", model[glc->next_model].name);
2388         for (i = 0; i < NODE_COUNT; i++) {
2389             if (glc->node[i] == ZERO)
2390                 printf("Z");
2391             else if (glc->node[i] == LEFT)
2392                 printf("L");
2393             else if (glc->node[i] == PIN)
2394                 printf("P");
2395             else if (glc->node[i] == RIGHT)
2396                 printf("R");
2397             /*
2398               else
2399               printf("%f", node[i].curAngle);
2400             */
2401             if (i < NODE_COUNT - 1)
2402                 printf(" ");
2403         }
2404         printf("\n");
2405         break;
2406       case 'f':
2407         glc->fullscreen = 1 - glc->fullscreen;
2408         if (glc->fullscreen) {
2409             glc->old_width = glc->width;
2410             glc->old_height = glc->height;
2411             glutFullScreen();
2412         } else {
2413             glutReshapeWindow(glc->old_width, glc->old_height);
2414             glutPositionWindow(50,50);
2415         }
2416         break;
2417       case 't':
2418         titles = 1 - titles;
2419         if (interactive || glc->paused)
2420             glutPostRedisplay();
2421         break;
2422       case 'a':
2423         altcolour = 1 - altcolour;
2424         break;
2425       case 'z':
2426         zoom += 1.0;
2427         glsnake_reshape(glc->width, glc->height);
2428         break;
2429       case 'Z':
2430         zoom -= 1.0;
2431         glsnake_reshape(glc->width, glc->height);
2432         break;
2433       default:
2434         break;
2435     }
2436 }
2437
2438 void ui_special(int key, int x, int y) {
2439     int i;
2440     float *destAngle = &(model[glc->next_model].node[glc->selected]);
2441     int unknown_key = 0;
2442
2443     if (interactive) {
2444         switch (key) {
2445           case GLUT_KEY_UP:
2446             glc->selected = (glc->selected + (NODE_COUNT - 2)) % (NODE_COUNT - 1);
2447             break;
2448           case GLUT_KEY_DOWN:
2449             glc->selected = (glc->selected + 1) % (NODE_COUNT - 1);
2450             break;
2451           case GLUT_KEY_LEFT:
2452             *destAngle = fmod(*destAngle+(LEFT), 360);
2453             glc->morphing = glc->new_morph = 1;
2454             break;
2455           case GLUT_KEY_RIGHT:
2456             *destAngle = fmod(*destAngle+(RIGHT), 360);
2457             glc->morphing = glc->new_morph = 1;
2458             break;
2459           case GLUT_KEY_HOME:
2460             start_morph(STRAIGHT_MODEL, 0);
2461             break;
2462           default:
2463             unknown_key = 1;
2464             break;
2465         }
2466     }
2467     calc_snake_metrics();
2468
2469     if (!unknown_key)
2470         glutPostRedisplay();
2471 }
2472
2473 void ui_mouse(int button, int state, int x, int y) {
2474     if (button==0) {
2475         switch (state) {
2476           case GLUT_DOWN:
2477             dragging = 1;
2478             m_s[0] = M_SQRT1_2 * 
2479                 (x - (glc->width / 2.0)) / (glc->width / 2.0);
2480             m_s[1] = M_SQRT1_2 * 
2481                 ((glc->height / 2.0) - y) / (glc->height / 2.0);
2482             m_s[2] = sqrt(1-(m_s[0]*m_s[0]+m_s[1]*m_s[1]));
2483             break;
2484           case GLUT_UP:
2485             dragging = 0;
2486             oldquat[0] = cumquat[0];
2487             oldquat[1] = cumquat[1];
2488             oldquat[2] = cumquat[2];
2489             oldquat[3] = cumquat[3];
2490             break;
2491           default:
2492             break;
2493         }
2494     }
2495     glutPostRedisplay();
2496 }
2497
2498 void ui_motion(int x, int y) {
2499     double norm;
2500     float q[4];
2501     
2502     if (dragging) {
2503         /* construct the motion end vector from the x,y position on the
2504          * window */
2505         m_e[0] = (x - (glc->width/ 2.0)) / (glc->width / 2.0);
2506         m_e[1] = ((glc->height / 2.0) - y) / (glc->height / 2.0);
2507         /* calculate the normal of the vector... */
2508         norm = m_e[0] * m_e[0] + m_e[1] * m_e[1];
2509         /* check if norm is outside the sphere and wraparound if necessary */
2510         if (norm > 1.0) {
2511             m_e[0] = -m_e[0];
2512             m_e[1] = -m_e[1];
2513             m_e[2] = sqrt(norm - 1);
2514         } else {
2515             /* the z value comes from projecting onto an elliptical spheroid */
2516             m_e[2] = sqrt(1 - norm);
2517         }
2518
2519         /* now here, build a quaternion from m_s and m_e */
2520         q[0] = m_s[1] * m_e[2] - m_s[2] * m_e[1];
2521         q[1] = m_s[2] * m_e[0] - m_s[0] * m_e[2];
2522         q[2] = m_s[0] * m_e[1] - m_s[1] * m_e[0];
2523         q[3] = m_s[0] * m_e[0] + m_s[1] * m_e[1] + m_s[2] * m_e[2];
2524
2525         /* new rotation is the product of the new one and the old one */
2526         cumquat[0] = q[3] * oldquat[0] + q[0] * oldquat[3] + 
2527             q[1] * oldquat[2] - q[2] * oldquat[1];
2528         cumquat[1] = q[3] * oldquat[1] + q[1] * oldquat[3] + 
2529             q[2] * oldquat[0] - q[0] * oldquat[2];
2530         cumquat[2] = q[3] * oldquat[2] + q[2] * oldquat[3] + 
2531             q[0] * oldquat[1] - q[1] * oldquat[0];
2532         cumquat[3] = q[3] * oldquat[3] - q[0] * oldquat[0] - 
2533             q[1] * oldquat[1] - q[2] * oldquat[2];
2534         
2535         calc_rotation();
2536     }
2537     glutPostRedisplay();
2538 }
2539
2540 void ui_init(int * argc, char ** argv) {
2541     glutInit(argc, argv);
2542     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
2543     glutInitWindowSize(glc->width, glc->height);
2544     glc->window = glutCreateWindow("glsnake");
2545
2546     glutDisplayFunc(glsnake_display);
2547     glutReshapeFunc(glsnake_reshape);
2548     glutIdleFunc(glsnake_idle);
2549     glutKeyboardFunc(ui_keyboard);
2550     glutSpecialFunc(ui_special);
2551     glutMouseFunc(ui_mouse);
2552     glutMotionFunc(ui_motion);
2553
2554     yangvel = DEF_YANGVEL;
2555     zangvel = DEF_ZANGVEL;
2556     explode = DEF_EXPLODE;
2557     angvel = DEF_ANGVEL;
2558     statictime = DEF_STATICTIME;
2559     altcolour = DEF_ALTCOLOUR;
2560     titles = DEF_TITLES;
2561     interactive = DEF_INTERACTIVE;
2562     zoom = DEF_ZOOM;
2563     wireframe = DEF_WIREFRAME;
2564 }
2565 #endif /* HAVE_GLUT */