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