From http://www.jwz.org/xscreensaver/xscreensaver-5.37.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 refresh_glsnake 0
148 #define release_glsnake 0
149 #define glsnake_handle_event 0
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, NULL);
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 w, int h) 
1772 {
1773     glViewport(0, 0, (GLint) w, (GLint) h);
1774     glMatrixMode(GL_PROJECTION);
1775     glLoadIdentity();
1776     /* jwz: 0.05 was too close (left black rectangles) */
1777     gluPerspective(zoom, (GLdouble) w / (GLdouble) h, 1.0, 100.0);
1778     gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1779     glMatrixMode(GL_MODELVIEW);
1780     /*gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);*/
1781     glLoadIdentity();
1782 #ifdef HAVE_GLUT
1783     bp->width = w;
1784     bp->height = h;
1785 #endif
1786 }
1787
1788 /* Returns the new dst_dir for the given src_dir and dst_dir */
1789 static int cross_product(int src_dir, int dst_dir) 
1790 {
1791     return X_MASK*(GETSCALAR(src_dir,Y_MASK) * GETSCALAR(dst_dir,Z_MASK) -
1792                    GETSCALAR(src_dir,Z_MASK) * GETSCALAR(dst_dir,Y_MASK))+ 
1793         Y_MASK*(GETSCALAR(src_dir,Z_MASK) * GETSCALAR(dst_dir,X_MASK) -
1794                 GETSCALAR(src_dir,X_MASK) * GETSCALAR(dst_dir,Z_MASK))+ 
1795         Z_MASK*(GETSCALAR(src_dir,X_MASK) * GETSCALAR(dst_dir,Y_MASK) -
1796                 GETSCALAR(src_dir,Y_MASK) * GETSCALAR(dst_dir,X_MASK));
1797 }
1798
1799 /* calculate orthogonal snake metrics
1800  *  is_legal  = true if model does not pass through itself
1801  *  is_cyclic = true if last node connects back to first node
1802  *  last_turn = for cyclic snakes, specifes what the 24th turn would be
1803  */
1804 static void calc_snake_metrics(struct glsnake_cfg *bp) 
1805 {
1806     int srcDir, dstDir;
1807     int i, x, y, z;
1808     int prevSrcDir = -Y_MASK;
1809     int prevDstDir = Z_MASK;
1810     int grid[25][25][25];
1811     
1812     /* zero the grid */
1813     memset(&grid, 0, sizeof(int) * 25*25*25);
1814     
1815     bp->is_legal = 1;
1816     x = y = z = 12;
1817     
1818     /* trace path of snake - and keep record for is_legal */
1819     for (i = 0; i < NODE_COUNT - 1; i++) {
1820         /*int ang_card;*/ /* cardinal direction of node angle */
1821         /* establish new state vars */
1822         srcDir = -prevDstDir;
1823         x += GETSCALAR(prevDstDir, X_MASK);
1824         y += GETSCALAR(prevDstDir, Y_MASK);
1825         z += GETSCALAR(prevDstDir, Z_MASK);
1826
1827         switch ((int) model[bp->next_model].node[i]) {
1828           case (int) (ZERO):
1829             dstDir = -prevSrcDir;
1830             break;
1831           case (int) (PIN):
1832             dstDir = prevSrcDir;
1833             break;
1834           case (int) (RIGHT):
1835           case (int) (LEFT):
1836             dstDir = cross_product(prevSrcDir, prevDstDir);
1837             if (model[bp->next_model].node[i] == (int) (RIGHT))
1838                 dstDir = -dstDir;
1839             break;
1840           default:
1841             /* Prevent spurious "might be used 
1842              * uninitialised" warnings when compiling
1843              * with -O2 */
1844             dstDir = 0;
1845             break;
1846         }
1847         
1848         if (grid[x][y][z] == 0)
1849             grid[x][y][z] = srcDir + dstDir;
1850         else if (grid[x][y][z] + srcDir + dstDir == 0)
1851             grid[x][y][z] = 8;
1852         else
1853             bp->is_legal = 0;
1854         
1855         prevSrcDir = srcDir;
1856         prevDstDir = dstDir;
1857     }   
1858     
1859     /* determine if the snake is cyclic */
1860     bp->is_cyclic = (dstDir == Y_MASK && x == 12 && y == 11 && z == 12);
1861     
1862     /* determine last_turn */
1863     bp->last_turn = -1;
1864     if (bp->is_cyclic)
1865         switch (srcDir) {
1866           case -Z_MASK: bp->last_turn = ZERO; break;
1867           case Z_MASK:  bp->last_turn = PIN; break;
1868           case X_MASK:  bp->last_turn = LEFT; break;
1869           case -X_MASK: bp->last_turn = RIGHT; break;
1870         }
1871 }
1872
1873 /* work out how far through the current morph we are */
1874 static float morph_percent(struct glsnake_cfg *bp) 
1875 {
1876     float retval;
1877     int i;
1878
1879     /* extend this function later with a case statement for each of the
1880      * morph schemes */
1881
1882     /* when morphing all nodes at once, the longest morph will be the node
1883      * that needs to rotate 180 degrees.  For each node, work out how far it
1884      * has to go, and store the maximum rotation and current largest angular
1885      * difference, returning the angular difference over the maximum. */
1886     {
1887         float rot_max = 0.0, ang_diff_max = 0.0;
1888
1889         for (i = 0; i < NODE_COUNT - 1; i++) {
1890             float rot, ang_diff;
1891
1892             /* work out the maximum rotation this node has to go through
1893              * from the previous to the next model, taking into account that
1894              * the snake always morphs through the smaller angle */
1895             rot = fabs(model[bp->prev_model].node[i] -
1896                        model[bp->next_model].node[i]);
1897             if (rot > 180.0) rot = 180.0 - rot;
1898             /* work out the difference between the current position and the
1899              * target */
1900             ang_diff = fabs(bp->node[i] -
1901                             model[bp->next_model].node[i]);
1902             if (ang_diff > 180.0) ang_diff = 180.0 - ang_diff;
1903             /* if it's the biggest so far, record it */
1904             if (rot > rot_max) rot_max = rot;
1905             if (ang_diff > ang_diff_max) ang_diff_max = ang_diff;
1906         }
1907         
1908         /* ang_diff / rot approaches 0, we want the complement */
1909         retval = 1.0 - (ang_diff_max / rot_max);
1910         /* protect against naan */
1911
1912 /* Apparently some systems (Solaris) don't have isinf() */
1913 #undef isinf
1914 #define isinf(x) (((x) > 999999999999.9) || ((x) < -999999999999.9))
1915
1916         if (isnan(retval) || isinf(retval)) retval = 1.0;
1917     }
1918     /*printf("morph_pct = %f\n", retval);*/
1919     return retval;
1920 }
1921
1922 static void morph_colour(struct glsnake_cfg *bp) 
1923 {
1924     float percent, compct; /* complement of percentage */
1925
1926     percent = morph_percent(bp);
1927     compct = 1.0 - percent;
1928
1929     bp->colour[0][0] = colour[bp->prev_colour][0][0] * compct + colour[bp->next_colour][0][0] * percent;
1930     bp->colour[0][1] = colour[bp->prev_colour][0][1] * compct + colour[bp->next_colour][0][1] * percent;
1931     bp->colour[0][2] = colour[bp->prev_colour][0][2] * compct + colour[bp->next_colour][0][2] * percent;
1932     bp->colour[0][3] = colour[bp->prev_colour][0][3] * compct + colour[bp->next_colour][0][3] * percent;
1933
1934     bp->colour[1][0] = colour[bp->prev_colour][1][0] * compct + colour[bp->next_colour][1][0] * percent;
1935     bp->colour[1][1] = colour[bp->prev_colour][1][1] * compct + colour[bp->next_colour][1][1] * percent;
1936     bp->colour[1][2] = colour[bp->prev_colour][1][2] * compct + colour[bp->next_colour][1][2] * percent;
1937     bp->colour[1][3] = colour[bp->prev_colour][1][3] * compct + colour[bp->next_colour][1][3] * percent;
1938 }
1939
1940 /* Start morph process to this model */
1941 static void start_morph(struct glsnake_cfg *bp, 
1942                         unsigned int model_index, int immediate)
1943 {
1944     /* if immediate, don't bother morphing, go straight to the next model */
1945     if (immediate) {
1946         int i;
1947
1948         for (i = 0; i < NODE_COUNT; i++)
1949             bp->node[i] = model[model_index].node[i];
1950     }
1951
1952     bp->prev_model = bp->next_model;
1953     bp->next_model = model_index;
1954     bp->prev_colour = bp->next_colour;
1955
1956     calc_snake_metrics(bp);
1957     if (!bp->is_legal)
1958         bp->next_colour = COLOUR_INVALID;
1959     else if (altcolour)
1960         bp->next_colour = COLOUR_AUTHENTIC;
1961     else if (bp->is_cyclic)
1962         bp->next_colour = COLOUR_CYCLIC;
1963     else
1964         bp->next_colour = COLOUR_ACYCLIC;
1965
1966     if (immediate) {
1967         bp->colour[0][0] = colour[bp->next_colour][0][0];
1968         bp->colour[0][1] = colour[bp->next_colour][0][1];
1969         bp->colour[0][2] = colour[bp->next_colour][0][2];
1970         bp->colour[0][3] = colour[bp->next_colour][0][3];
1971         bp->colour[1][0] = colour[bp->next_colour][1][0];
1972         bp->colour[1][1] = colour[bp->next_colour][1][1];
1973         bp->colour[1][2] = colour[bp->next_colour][1][2];
1974         bp->colour[1][3] = colour[bp->next_colour][1][3];
1975     }
1976     bp->morphing = 1;
1977
1978     morph_colour(bp);
1979 }
1980
1981 #if 0
1982 /* Returns morph progress */
1983 static float morph(long iter_msec) 
1984 {
1985     /* work out the maximum angle for this iteration */
1986     int still_morphing;
1987     float iter_angle_max, largest_diff, largest_progress;
1988     int i;
1989
1990     if (bp->new_morph)
1991         bp->new_morph = 0;
1992         
1993     iter_angle_max = 90.0 * (angvel/1000.0) * iter_msec;
1994         
1995     still_morphing = 0;
1996     largest_diff = largest_progress = 0.0;
1997     for (i = 0; i < NODE_COUNT; i++) {
1998         float curAngle = bp->node[i];
1999         float destAngle = model[bp->next_model].node[i];
2000         if (curAngle != destAngle) {
2001             still_morphing = 1;
2002             if (fabs(curAngle-destAngle) <= iter_angle_max)
2003                 bp->node[i] = destAngle;
2004             else if (fmod(curAngle-destAngle+360,360) > 180)
2005                 bp->node[i] = fmod(curAngle + iter_angle_max, 360);
2006             else
2007                 bp->node[i] = fmod(curAngle+360 - iter_angle_max, 360);
2008             largest_diff = MAX(largest_diff, fabs(destAngle-bp->node[i]));
2009             largest_progress = MAX(largest_diff, fabs(bp->node[i] - model[bp->prev_model].node[i]));
2010         }
2011     }
2012         
2013     return MIN(largest_diff / largest_progress, 1.0);
2014 }
2015 #endif
2016
2017
2018 #ifdef HAVE_GLUT
2019 static void glsnake_idle();
2020
2021 static restore_idle(int v __attribute__((__unused__)))
2022 {
2023     glutIdleFunc(glsnake_idle);
2024 }
2025 #endif
2026
2027 static void quick_sleep(void)
2028 {
2029 #ifdef HAVE_GLUT
2030     /* By using glutTimerFunc we can keep responding to 
2031      * mouse and keyboard events, unlike using something like
2032      * usleep. */
2033     glutIdleFunc(NULL);
2034     glutTimerFunc(1, restore_idle, 0);
2035 #else
2036     usleep(1);
2037 #endif
2038 }
2039
2040 static void glsnake_idle(
2041 #ifndef HAVE_GLUT
2042                   struct glsnake_cfg * bp
2043 #endif
2044                   ) 
2045 {
2046     /* time since last iteration */
2047     long iter_msec;
2048     /* time since the beginning of last morph */
2049     long morf_msec;
2050     float iter_angle_max;
2051     snaketime current_time;
2052     /*    morphFunc transition; */
2053     int still_morphing;
2054     int i;
2055     
2056     /* Do nothing to the model if we are paused */
2057     if (bp->paused) {
2058         /* Avoid busy waiting when nothing is changing */
2059         quick_sleep();
2060 #ifdef HAVE_GLUT
2061         glutSwapBuffers();
2062         glutPostRedisplay();
2063 #endif
2064         return;
2065     }
2066
2067     /* <spiv> Well, ftime gives time with millisecond resolution.
2068      * <spiv> (or worse, perhaps... who knows what the OS will do)
2069      * <spiv> So if no discernable amount of time has passed:
2070      * <spiv>   a) There's no point updating the screen, because
2071      *             it would be the same
2072      * <spiv>   b) The code will divide by zero
2073      */
2074     gettime(&current_time);
2075     
2076     iter_msec = (long) GETMSECS(current_time) - GETMSECS(bp->last_iteration) + 
2077         ((long) GETSECS(current_time) - GETSECS(bp->last_iteration)) * 1000L;
2078
2079     if (iter_msec) {
2080         /* save the current time */
2081         memcpy(&bp->last_iteration, &current_time, sizeof(snaketime));
2082         
2083         /* work out if we have to switch models */
2084         morf_msec = GETMSECS(bp->last_iteration) - GETMSECS(bp->last_morph) +
2085             ((long) (GETSECS(bp->last_iteration)-GETSECS(bp->last_morph)) * 1000L);
2086
2087         if ((morf_msec > statictime) && !interactive && !bp->morphing) {
2088             /*printf("starting morph\n");*/
2089             memcpy(&bp->last_morph, &(bp->last_iteration), sizeof(bp->last_morph));
2090             start_morph(bp, RAND(models), 0);
2091         }
2092         
2093         if (interactive && !bp->morphing) {
2094             quick_sleep();
2095             return;
2096         }
2097         
2098         /*      if (!bp->dragging && !bp->interactive) { */
2099         if (!interactive) {
2100             
2101             yspin += 360/((1000/yangvel)/iter_msec);
2102             zspin += 360/((1000/zangvel)/iter_msec);
2103             /*
2104             yspin += 360 * (yangvel/1000.0) * iter_msec;
2105             zspin += 360 * (zangvel/1000.0) * iter_msec;
2106             */
2107             
2108             /*printf("yspin: %f, zspin: %f\n", yspin, zspin);*/
2109
2110         }
2111
2112         /* work out the maximum angle we could turn this node in this
2113          * timeslice, iter_msec milliseconds long */
2114         iter_angle_max = 90.0 * (angvel/1000.0) * iter_msec;
2115
2116         still_morphing = 0;
2117         for (i = 0; i < NODE_COUNT; i++) {
2118             float cur_angle = bp->node[i];
2119             float dest_angle = model[bp->next_model].node[i];
2120             if (cur_angle != dest_angle) {
2121                 still_morphing = 1;
2122                 if (fabs(cur_angle - dest_angle) <= iter_angle_max)
2123                     bp->node[i] = dest_angle;
2124                 else if (fmod(cur_angle - dest_angle + 360, 360) > 180)
2125                     bp->node[i] = fmod(cur_angle + iter_angle_max, 360);
2126                 else
2127                     bp->node[i] = fmod(cur_angle + 360 - iter_angle_max, 360);
2128             }
2129         }
2130
2131         if (!still_morphing)
2132             bp->morphing = 0;
2133
2134         /* colour cycling */
2135         morph_colour(bp);
2136         
2137 #ifdef HAVE_GLUT
2138         glutSwapBuffers();
2139         glutPostRedisplay();
2140 #endif
2141     } else {
2142         /* We are going too fast, so we may as well let the 
2143          * cpu relax a little by sleeping for a millisecond. */
2144         quick_sleep();
2145     }
2146 }
2147
2148 /* wot draws it */
2149 ENTRYPOINT void glsnake_display(
2150 #ifndef HAVE_GLUT
2151                      ModeInfo * mi
2152 #endif
2153                      ) 
2154 {
2155 #ifndef HAVE_GLUT
2156     struct glsnake_cfg * bp = &glc[MI_SCREEN(mi)];
2157     Display * dpy = MI_DISPLAY(mi);
2158     Window window = MI_WINDOW(mi);
2159 #endif
2160
2161     int i;
2162     float ang;
2163     float positions[NODE_COUNT][4]; /* origin points for each node */
2164     float com[4]; /* it's the CENTRE of MASS */
2165
2166 #ifndef HAVE_GLUT
2167     if (!bp->glx_context)
2168         return;
2169
2170     glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
2171 #endif
2172     
2173     gl_init(mi);
2174
2175     /* clear the buffer */
2176     glClear((GLbitfield) GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2177     
2178     /* go into the modelview stack */
2179     glMatrixMode(GL_MODELVIEW);
2180     glLoadIdentity();
2181     
2182     /* get the centre of each node, by moving through the snake and
2183      * performing the rotations, then grabbing the matrix at each point
2184      * and applying it to the origin */
2185     glPushMatrix();
2186
2187 #ifdef HAVE_GLUT
2188     /* apply the mouse drag rotation */
2189     ui_mousedrag();
2190 #endif
2191     
2192     /* apply the continuous rotation */
2193     glRotatef(yspin, 0.0, 1.0, 0.0); 
2194     glRotatef(zspin, 0.0, 0.0, 1.0); 
2195     
2196     com[0] = 0.0;
2197     com[1] = 0.0;
2198     com[2] = 0.0;
2199     com[3] = 0.0;
2200     for (i = 0; i < NODE_COUNT; i++) {
2201         float rotmat[16];
2202
2203         ang = bp->node[i];
2204
2205         /*printf("ang = %f\n", ang);*/
2206         
2207         glTranslatef(0.5, 0.5, 0.5);            /* move to center */
2208         glRotatef(90.0, 0.0, 0.0, -1.0);        /* reorient  */
2209         glTranslatef(1.0 + explode, 0.0, 0.0);  /* move to new pos. */
2210         glRotatef(180.0 + ang, 1.0, 0.0, 0.0);  /* pivot to new angle */
2211         glTranslatef(-0.5, -0.5, -0.5);         /* return from center */
2212
2213         glGetFloatv(GL_MODELVIEW_MATRIX, rotmat);
2214
2215         matmult_origin(rotmat, positions[i]);
2216
2217         /*printf("positions %f %f %f %f\n", positions[i][0], positions[i][1], positions[i][2], positions[i][3]);*/
2218
2219         com[0] += positions[i][0];
2220         com[1] += positions[i][1];
2221         com[2] += positions[i][2];
2222         com[3] += positions[i][3];
2223     }
2224     glPopMatrix();
2225     com[0] /= NODE_COUNT;
2226     com[1] /= NODE_COUNT;
2227     com[2] /= NODE_COUNT;
2228     com[3] /= NODE_COUNT;
2229
2230     com[0] /= com[3];
2231     com[1] /= com[3];
2232     com[2] /= com[3];
2233
2234     /*printf("com: %f, %f, %f, %f\n", com[0], com[1], com[2], com[3]);*/
2235
2236 #if MAGICAL_RED_STRING
2237     glPushMatrix();
2238     glTranslatef(-com[0], -com[1], -com[2]);
2239
2240     glDisable(GL_LIGHTING);
2241     glColor4f(1.0, 0.0, 0.0, 1.0);
2242     glBegin(GL_LINE_STRIP);
2243     for (i = 0; i < NODE_COUNT - 1; i++) {
2244         glVertex3fv(positions[i]);
2245     }
2246     glEnd();
2247     glEnable(GL_LIGHTING);
2248     /*glTranslatef(com[0], com[1], com[2]);*/
2249     glPopMatrix();
2250 #endif
2251
2252     glPushMatrix();
2253     glTranslatef(-com[0], -com[1], -com[2]);
2254
2255 #ifdef HAVE_GLUT
2256     /* apply the mouse drag rotation */
2257     ui_mousedrag();
2258 #endif
2259     
2260     /* apply the continuous rotation */
2261     glRotatef(yspin, 0.0, 1.0, 0.0); 
2262     glRotatef(zspin, 0.0, 0.0, 1.0); 
2263
2264 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
2265     {
2266       GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
2267       int o = (int) current_device_rotation();
2268       if (o != 0 && o != 180 && o != -180)
2269         glScalef (1/h, 1/h, 1/h);
2270     }
2271 # endif
2272
2273     /* now draw each node along the snake -- this is quite ugly :p */
2274     mi->polygon_count = 0;
2275     for (i = 0; i < NODE_COUNT; i++) {
2276         /* choose a colour for this node */
2277         if ((i == bp->selected || i == bp->selected+1) && interactive)
2278             /* yellow */
2279             glColor4f(1.0, 1.0, 0.0, 1.0);
2280         else {
2281             /*glColor4fv(bp->colour[(i+1)%2]);*/
2282             glMaterialfv(GL_FRONT, GL_AMBIENT, bp->colour[(i+1)%2]);
2283             glMaterialfv(GL_FRONT, GL_DIFFUSE, bp->colour[(i+1)%2]);
2284             /*glMaterialfv(GL_FRONT, GL_SPECULAR, bp->colour[(i+1)%2]);*/
2285         }
2286
2287         /* draw the node */
2288         if (wireframe)
2289             glCallList(bp->node_wire);
2290         else
2291             glCallList(bp->node_solid);
2292         mi->polygon_count += bp->node_polys;
2293
2294         /* now work out where to draw the next one */
2295         
2296         /* Interpolate between models */
2297         ang = bp->node[i];
2298         
2299         glTranslatef(0.5, 0.5, 0.5);            /* move to center */
2300         glRotatef(90.0, 0.0, 0.0, -1.0);        /* reorient  */
2301         glTranslatef(1.0 + explode, 0.0, 0.0);  /* move to new pos. */
2302         glRotatef(180.0 + ang, 1.0, 0.0, 0.0);  /* pivot to new angle */
2303         glTranslatef(-0.5, -0.5, -0.5);         /* return from center */
2304     }
2305
2306     glPopMatrix();
2307     
2308     if (titles)
2309 #ifdef HAVE_GLUT
2310         draw_title();
2311 #else
2312         draw_title(mi);
2313 #endif
2314
2315 #ifndef HAVE_GLUT
2316         glsnake_idle(bp);
2317         if (mi->fps_p) do_fps(mi);
2318 #endif
2319     
2320     glFlush();
2321 #ifdef HAVE_GLUT
2322     glutSwapBuffers();
2323 #else
2324     glXSwapBuffers(dpy, window);
2325 #endif
2326 }
2327
2328 #ifdef HAVE_GLUT
2329 /* anything that needs to be cleaned up goes here */
2330 static void unmain() 
2331 {
2332     glutDestroyWindow(bp->window);
2333     free(bp);
2334 }
2335
2336 static void ui_init(int *, char **);
2337
2338 int main(int argc, char ** argv) 
2339 {
2340     bp = malloc(sizeof(struct glsnake_cfg));
2341     memset(bp, 0, sizeof(struct glsnake_cfg));
2342
2343     bp->width = 640;
2344     bp->height = 480;
2345     
2346     ui_init(&argc, argv);
2347
2348     gettime(&bp->last_iteration);
2349     memcpy(&bp->last_morph, &bp->last_iteration, sizeof(snaketime));
2350     srand((unsigned int)GETSECS(bp->last_iteration));
2351
2352     bp->prev_colour = bp->next_colour = COLOUR_ACYCLIC;
2353     bp->next_model = RAND(models);
2354     bp->prev_model = 0;
2355     start_morph(bp->prev_model, 1);     
2356
2357     glsnake_init();
2358     
2359     atexit(unmain);
2360     glutSwapBuffers();
2361     glutMainLoop();
2362     
2363     return 0;
2364 }
2365 #endif
2366
2367 /*
2368  * GLUT FUNCTIONS
2369  */
2370
2371 #ifdef HAVE_GLUT
2372
2373 /* trackball quaternions */
2374 static float cumquat[4] = {0.0,0.0,0.0,0.0}, oldquat[4] = {0.0,0.0,0.0,0.1};
2375
2376 /* rotation matrix */
2377 static float rotation[16];
2378
2379 /* mouse drag vectors: start and end */
2380 static float mouse_start[3], mouse_end[3];
2381
2382 /* dragging boolean */
2383 static int dragging = 0;
2384
2385 /* this function calculates the rotation matrix based on the quaternions
2386  * generated from the mouse drag vectors */
2387 static void calc_rotation() 
2388 {
2389     double Nq, s;
2390     double xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz;
2391
2392     /* this bit ripped from Shoemake's quaternion notes from SIGGRAPH */
2393     Nq = cumquat[0] * cumquat[0] + cumquat[1] * cumquat[1] +
2394         cumquat[2] * cumquat[2] + cumquat[3] * cumquat[3];
2395     s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
2396     xs = cumquat[0] *  s; ys = cumquat[1] *  s; zs = cumquat[2] * s;
2397     wx = cumquat[3] * xs; wy = cumquat[3] * ys; wz = cumquat[3] * zs;
2398     xx = cumquat[0] * xs; xy = cumquat[0] * ys; xz = cumquat[0] * zs;
2399     yy = cumquat[1] * ys; yz = cumquat[1] * zs; zz = cumquat[2] * zs;
2400
2401     rotation[0] = 1.0 - (yy + zz);
2402     rotation[1] = xy + wz;
2403     rotation[2] = xz - wy;
2404     rotation[4] = xy - wz;
2405     rotation[5] = 1.0 - (xx + zz);
2406     rotation[6] = yz + wx;
2407     rotation[8] = xz + wy;
2408     rotation[9] = yz - wx;
2409     rotation[10] = 1.0 - (xx + yy);
2410     rotation[3] = rotation[7] = rotation[11] = 0.0;
2411     rotation[12] = rotation[13] = rotation[14] = 0.0;
2412     rotation[15] = 1.0;
2413 }
2414
2415 static inline void ui_mousedrag() 
2416 {
2417     glMultMatrixf(rotation);
2418 }
2419
2420 static void ui_keyboard(unsigned char c, int x__attribute__((__unused__)), int y __attribute__((__unused__)))
2421 {
2422     int i;
2423     
2424     switch (c) {
2425       case 27:  /* ESC */
2426       case 'q':
2427         exit(0);
2428         break;
2429       case 'e':
2430         explode += DEF_EXPLODE;
2431         glutPostRedisplay();
2432         break;
2433       case 'E':
2434         explode -= DEF_EXPLODE;
2435         if (explode < 0.0) explode = 0.0;
2436         glutPostRedisplay();
2437         break;
2438       case '.':
2439         /* next model */
2440         bp->next_model++;
2441         bp->next_model %= models;
2442         start_morph(bp->next_model, 0);
2443         
2444         /* Reset last_morph time */
2445         gettime(&bp->last_morph);                       
2446         break;
2447       case ',':
2448         /* previous model */
2449         bp->next_model = (bp->next_model + (int)models - 1) % (int)models;
2450         start_morph(bp->next_model, 0);
2451         
2452         /* Reset bp->last_morph time */
2453         gettime(&bp->last_morph);                       
2454         break;
2455       case '+':
2456         angvel += DEF_ANGVEL;
2457         break;
2458       case '-':
2459         if (angvel > DEF_ANGVEL)
2460             angvel -= DEF_ANGVEL;
2461         break;
2462       case 'i':
2463         if (interactive) {
2464             /* Reset last_iteration and last_morph time */
2465             gettime(&bp->last_iteration);
2466             gettime(&bp->last_morph);
2467         }
2468         interactive = 1 - interactive;
2469         glutPostRedisplay();
2470         break;
2471       case 'w':
2472         wireframe = 1 - wireframe;
2473         if (wireframe)
2474             glDisable(GL_LIGHTING);
2475         else
2476             glEnable(GL_LIGHTING);
2477         glutPostRedisplay();
2478         break;
2479       case 'a':
2480         transparent = 1 - transparent;
2481         if (transparent) {
2482             glEnable(GL_BLEND);
2483         } else {
2484             glDisable(GL_BLEND);
2485         }
2486         break;
2487       case 'p':
2488         if (bp->paused) {
2489             /* unpausing, reset last_iteration and last_morph time */
2490             gettime(&bp->last_iteration);
2491             gettime(&bp->last_morph);
2492         }
2493         bp->paused = 1 - bp->paused;
2494         break;
2495       case 'd':
2496         /* dump the current model so we can add it! */
2497         printf("# %s\nnoname:\t", model[bp->next_model].name);
2498         {
2499             int i;
2500             
2501             for (i = 0; i < NODE_COUNT; i++) {
2502                 if (bp->node[i] == ZERO)
2503                     printf("Z");
2504                 else if (bp->node[i] == LEFT)
2505                     printf("L");
2506                 else if (bp->node[i] == PIN)
2507                     printf("P");
2508                 else if (bp->node[i] == RIGHT)
2509                     printf("R");
2510                 /*
2511                   else
2512                   printf("%f", node[i].curAngle);
2513                 */
2514                 if (i < NODE_COUNT - 1)
2515                     printf(" ");
2516             }
2517         }
2518         printf("\n");
2519         break;
2520       case 'f':
2521         bp->fullscreen = 1 - bp->fullscreen;
2522         if (bp->fullscreen) {
2523             bp->old_width = bp->width;
2524             bp->old_height = bp->height;
2525             glutFullScreen();
2526         } else {
2527             glutReshapeWindow(bp->old_width, bp->old_height);
2528             glutPositionWindow(50,50);
2529         }
2530         break;
2531       case 't':
2532         titles = 1 - titles;
2533         if (interactive || bp->paused)
2534             glutPostRedisplay();
2535         break;
2536       case 'c':
2537         altcolour = 1 - altcolour;
2538         break;
2539       case 'z':
2540         zoom += 1.0;
2541         glsnake_reshape(bp->width, bp->height);
2542         break;
2543       case 'Z':
2544         zoom -= 1.0;
2545         glsnake_reshape(bp->width, bp->height);
2546         break;
2547       default:
2548         break;
2549     }
2550 }
2551
2552 static void ui_special(int key, int x__attribute__((__unused__)), int y __attribute__((__unused__)))
2553 {
2554     float *destAngle = &(model[bp->next_model].node[bp->selected]);
2555     int unknown_key = 0;
2556
2557     if (interactive) {
2558         switch (key) {
2559           case GLUT_KEY_UP:
2560             bp->selected = (bp->selected + (NODE_COUNT - 2)) % (NODE_COUNT - 1);
2561             break;
2562           case GLUT_KEY_DOWN:
2563             bp->selected = (bp->selected + 1) % (NODE_COUNT - 1);
2564             break;
2565           case GLUT_KEY_LEFT:
2566             *destAngle = fmod(*destAngle+(LEFT), 360);
2567             bp->morphing = bp->new_morph = 1;
2568             break;
2569           case GLUT_KEY_RIGHT:
2570             *destAngle = fmod(*destAngle+(RIGHT), 360);
2571             bp->morphing = bp->new_morph = 1;
2572             break;
2573           case GLUT_KEY_HOME:
2574             start_morph(STRAIGHT_MODEL, 0);
2575             break;
2576           default:
2577             unknown_key = 1;
2578             break;
2579         }
2580     }
2581     calc_snake_metrics();
2582
2583     if (!unknown_key)
2584         glutPostRedisplay();
2585 }
2586
2587 static void ui_mouse(int button, int state, int x, int y) 
2588 {
2589     if (button==0) {
2590         switch (state) {
2591           case GLUT_DOWN:
2592             dragging = 1;
2593             mouse_start[0] = M_SQRT1_2 * 
2594                 (x - (bp->width / 2.0)) / (bp->width / 2.0);
2595             mouse_start[1] = M_SQRT1_2 * 
2596                 ((bp->height / 2.0) - y) / (bp->height / 2.0);
2597             mouse_start[2] = sqrt((double)(1-(mouse_start[0]*mouse_start[0]+mouse_start[1]*mouse_start[1])));
2598             break;
2599           case GLUT_UP:
2600             dragging = 0;
2601             oldquat[0] = cumquat[0];
2602             oldquat[1] = cumquat[1];
2603             oldquat[2] = cumquat[2];
2604             oldquat[3] = cumquat[3];
2605             break;
2606           default:
2607             break;
2608         }
2609     }
2610     glutPostRedisplay();
2611 }
2612
2613 static void ui_motion(int x, int y) 
2614 {
2615     double norm;
2616     float q[4];
2617     
2618     if (dragging) {
2619         /* construct the motion end vector from the x,y position on the
2620          * window */
2621         mouse_end[0] = M_SQRT1_2 * (x - (bp->width/ 2.0)) / (bp->width / 2.0);
2622         mouse_end[1] = M_SQRT1_2 * ((bp->height / 2.0) - y) / (bp->height / 2.0);
2623         /* calculate the normal of the vector... */
2624         norm = mouse_end[0] * mouse_end[0] + mouse_end[1] * mouse_end[1];
2625         /* check if norm is outside the sphere and wraparound if necessary */
2626         if (norm > 1.0) {
2627             mouse_end[0] = -mouse_end[0];
2628             mouse_end[1] = -mouse_end[1];
2629             mouse_end[2] = sqrt(norm - 1);
2630         } else {
2631             /* the z value comes from projecting onto an elliptical spheroid */
2632             mouse_end[2] = sqrt(1 - norm);
2633         }
2634
2635         /* now here, build a quaternion from mouse_start and mouse_end */
2636         q[0] = mouse_start[1] * mouse_end[2] - mouse_start[2] * mouse_end[1];
2637         q[1] = mouse_start[2] * mouse_end[0] - mouse_start[0] * mouse_end[2];
2638         q[2] = mouse_start[0] * mouse_end[1] - mouse_start[1] * mouse_end[0];
2639         q[3] = mouse_start[0] * mouse_end[0] + mouse_start[1] * mouse_end[1] + mouse_start[2] * mouse_end[2];
2640
2641         /* new rotation is the product of the new one and the old one */
2642         cumquat[0] = q[3] * oldquat[0] + q[0] * oldquat[3] + 
2643             q[1] * oldquat[2] - q[2] * oldquat[1];
2644         cumquat[1] = q[3] * oldquat[1] + q[1] * oldquat[3] + 
2645             q[2] * oldquat[0] - q[0] * oldquat[2];
2646         cumquat[2] = q[3] * oldquat[2] + q[2] * oldquat[3] + 
2647             q[0] * oldquat[1] - q[1] * oldquat[0];
2648         cumquat[3] = q[3] * oldquat[3] - q[0] * oldquat[0] - 
2649             q[1] * oldquat[1] - q[2] * oldquat[2];
2650         
2651         calc_rotation();
2652     }
2653     glutPostRedisplay();
2654 }
2655
2656 static void ui_init(int * argc, char ** argv) 
2657 {
2658     glutInit(argc, argv);
2659     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
2660     glutInitWindowSize(bp->width, bp->height);
2661     bp->window = glutCreateWindow("glsnake");
2662
2663     glutDisplayFunc(glsnake_display);
2664     glutReshapeFunc(glsnake_reshape);
2665     glutIdleFunc(glsnake_idle);
2666     glutKeyboardFunc(ui_keyboard);
2667     glutSpecialFunc(ui_special);
2668     glutMouseFunc(ui_mouse);
2669     glutMotionFunc(ui_motion);
2670
2671     yangvel = DEF_YANGVEL;
2672     zangvel = DEF_ZANGVEL;
2673     explode = DEF_EXPLODE;
2674     angvel = DEF_ANGVEL;
2675     statictime = DEF_STATICTIME;
2676     altcolour = DEF_ALTCOLOUR;
2677     titles = DEF_TITLES;
2678     interactive = DEF_INTERACTIVE;
2679     zoom = DEF_ZOOM;
2680     wireframe = DEF_WIREFRAME;
2681     transparent = DEF_TRANSPARENT;
2682 }
2683 #endif /* HAVE_GLUT */
2684
2685 XSCREENSAVER_MODULE ("GLSnake", glsnake)