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