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