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