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