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