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