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