source: trunk/third/xscreensaver/hacks/penrose.c @ 20148

Revision 20148, 38.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 4 -*- */
2/* penrose --- quasiperiodic tilings */
3
4/*  As reported in News of the Weird:
5
6          In April, Sir Roger Penrose, a British math professor who has worked
7          with Stephen Hawking on such topics as relativity, black holes, and
8          whether time has a beginning, filed a copyright-infringement lawsuit
9          against the Kimberly-Clark Corporation, which Penrose said copied a
10          pattern he created (a pattern demonstrating that "a nonrepeating
11          pattern could exist in nature") for its Kleenex quilted toilet paper.
12          Penrose said he doesn't like litigation but, "When it comes to the
13          population of Great Britain being invited by a multinational to wipe
14          their bottoms on what appears to be the work of a Knight of the
15          Realm, then a last stand must be taken."
16
17                                NOTW #491, 4-jul-1997, by Chuck Shepherd.
18                                http://www.nine.org/notw/notw.html
19 */
20
21#if 0
22static const char sccsid[] = "@(#)penrose.c     5.00 2000/11/01 xlockmore";
23#endif
24
25/*-
26 * Copyright (c) 1996 by Timo Korvola <tkorvola@dopey.hut.fi>
27 *
28 * Permission to use, copy, modify, and distribute this software and its
29 * documentation for any purpose and without fee is hereby granted,
30 * provided that the above copyright notice appear in all copies and that
31 * both that copyright notice and this permission notice appear in
32 * supporting documentation.
33 *
34 * This file is provided AS IS with no warranties of any kind.  The author
35 * shall have no liability with respect to the infringement of copyrights,
36 * trade secrets or any patents by this file or any part thereof.  In no
37 * event will the author be liable for any lost revenue or profits or
38 * other special, indirect and consequential damages.
39 *
40 * Revision History:
41 * 01-Nov-2000: Allocation checks
42 * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
43 * 09-Sep-1996: Written.
44 */
45
46/*-
47Be careful, this probably still has a few bugs (many of which may only
48appear with a very low probability).  These are seen with -verbose .
49If one of these are hit penrose will reinitialize.
50*/
51
52/*-
53 * See Onoda, Steinhardt, DiVincenzo and Socolar in
54 * Phys. Rev. Lett. 60, #25, 1988 or
55 * Strandburg in Computers in Physics, Sep/Oct 1991.
56 *
57 * This implementation uses the simpler version of the growth
58 * algorithm, i.e., if there are no forced vertices, a randomly chosen
59 * tile is added to a randomly chosen vertex (no preference for those
60 * 108 degree angles).
61 *
62 * There are two essential differences to the algorithm presented in
63 * the literature: First, we do not allow the tiling to enclose an
64 * untiled area.  Whenever this is in danger of happening, we just
65 * do not add the tile, hoping for a better random choice the next
66 * time.  Second, when choosing a vertex randomly, we will take
67 * one that lies within the viewport if available.  If this seems to
68 * cause enclosures in the forced rule case, we will allow invisible
69 * vertices to be chosen.
70 *
71 * Tiling is restarted whenever one of the following happens: there
72 * are no incomplete vertices within the viewport or the tiling has
73 * extended a window's length beyond the edge of the window
74 * horizontally or vertically or forced rule choice has failed 100
75 * times due to areas about to become enclosed.
76 *
77 * Introductory info:
78 * Science News March 23 1985 Vol 127, No. 12
79 * Science News July 16 1988 Vol 134, No. 3
80 * The Economist Sept 17 1988 pg. 100
81 *
82 */
83
84#ifdef STANDALONE
85#define MODE_penrose
86#define PROGCLASS "Penrose"
87#define HACK_INIT init_penrose
88#define HACK_DRAW draw_penrose
89#define penrose_opts xlockmore_opts
90#define DEFAULTS "*delay: 10000 \n" \
91 "*size: 40 \n" \
92 "*ncolors: 64 \n"
93#include "xlockmore.h"          /* from the xscreensaver distribution */
94#else /* !STANDALONE */
95#include "xlock.h"              /* from the xlockmore distribution */
96#endif /* !STANDALONE */
97
98#ifdef MODE_penrose
99
100#define DEF_AMMANN  "False"
101
102static Bool ammann;
103
104static XrmOptionDescRec opts[] =
105{
106        {(char *) "-ammann", (char *) ".penrose.ammann", XrmoptionNoArg, (caddr_t) "on"},
107        {(char *) "+ammann", (char *) ".penrose.ammann", XrmoptionNoArg, (caddr_t) "off"}
108};
109static argtype vars[] =
110{
111        {(caddr_t *) & ammann, (char *) "ammann", (char *) "Ammann", (char *) DEF_AMMANN, t_Bool}
112};
113static OptionStruct desc[] =
114{
115        {(char *) "-/+ammann", (char *) "turn on/off Ammann lines"}
116};
117
118ModeSpecOpt penrose_opts =
119{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
120
121#ifdef USE_MODULES
122ModStruct   penrose_description =
123{"penrose", "init_penrose", "draw_penrose", "release_penrose",
124 "init_penrose", "init_penrose", (char *) NULL, &penrose_opts,
125 10000, 1, 1, -40, 64, 1.0, "",
126 "Shows Penrose's quasiperiodic tilings", 0, NULL};
127
128#endif
129
130/*-
131 * Annoyingly the ANSI C library people have reserved all identifiers
132 * ending with _t for future use.  Hence we use _c as a suffix for
133 * typedefs (c for class, although this is not C++).
134 */
135
136#define MINSIZE 5
137
138/*-
139 * In theory one could fit 10 tiles to a single vertex.  However, the
140 * vertex rules only allow at most seven tiles to meet at a vertex.
141 */
142
143#define CELEBRATE 31415         /* This causes a pause, an error occurred. */
144#define COMPLETION 3141         /* This causes a pause, tiles filled up screen. */
145
146#define MAX_TILES_PER_VERTEX 7
147#define N_VERTEX_RULES 8
148#define ALLOC_NODE(type) (type *)malloc(sizeof (type))
149
150/*-
151 * These are used to specify directions.  They can also be used in bit
152 * masks to specify a combination of directions.
153 */
154#define S_LEFT 1
155#define S_RIGHT 2
156
157
158/*-
159 * We do not actually maintain objects corresponding to the tiles since
160 * we do not really need them and they would only consume memory and
161 * cause additional bookkeeping.  Instead we only have vertices, and
162 * each vertex lists the type of each adjacent tile as well as the
163 * position of the vertex on the tile (hereafter refered to as
164 * "corner").  These positions are numbered in counterclockwise order
165 * so that 0 is where two double arrows meet (see one of the
166 * articles).  The tile type and vertex number are stored in a single
167 * integer (we use char, and even most of it remains unused).
168 *
169 * The primary use of tile objects would be draw traversal, but we do
170 * not currently do redraws at all (we just start over).
171 */
172#define VT_CORNER_MASK 0x3
173#define VT_TYPE_MASK 0x4
174#define VT_THIN 0
175#define VT_THICK 0x4
176#define VT_BITS 3
177#define VT_TOTAL_MASK 0x7
178
179typedef unsigned char vertex_type_c;
180
181/*-
182 * These allow one to compute the types of the other corners of the tile.  If
183 * you are standing at a vertex of type vt looking towards the middle of the
184 * tile, VT_LEFT( vt) is the vertex on your left etc.
185 */
186#define VT_LEFT( vt) ((((vt) - 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK)))
187#define VT_RIGHT( vt) ((((vt) + 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK)))
188#define VT_FAR( vt) ((vt) ^ 2)
189
190
191/*-
192 * Since we do not do redraws, we only store the vertices we need.  These are
193 * the ones with still some empty space around them for the growth algorithm
194 * to fill.
195 *
196 * Here we use a doubly chained ring-like structure as vertices often need
197 * to be removed or inserted (they are kept in geometrical order
198 * circling the tiled area counterclockwise).  The ring is refered to by
199 * a pointer to one more or less random node.  When deleting nodes one
200 * must make sure that this pointer continues to refer to a valid
201 * node.  A vertex count is maintained to make it easier to pick
202 * vertices randomly.
203 */
204typedef struct forced_node forced_node_c;
205
206typedef struct fringe_node {
207        struct fringe_node *prev;
208        struct fringe_node *next;
209        /* These are numbered counterclockwise.  The gap, if any, lies
210           between the last and first tiles.  */
211        vertex_type_c tiles[MAX_TILES_PER_VERTEX];
212        int         n_tiles;
213        /* A bit mask used to indicate vertex rules that are still applicable for
214           completing this vertex.  Initialize this to (1 << N_VERTEX_RULES) - 1,
215           i.e., all ones, and the rule matching functions will automatically mask
216           out rules that no longer match. */
217        unsigned char rule_mask;
218        /* If the vertex is on the forced vertex list, this points to the
219           pointer to the appropriate node in the list.  To remove the
220           vertex from the list just set *list_ptr to the next node,
221           deallocate and decrement node count. */
222        struct forced_node **list_ptr;
223        /* Screen coordinates. */
224        XPoint      loc;
225        /* We also keep track of 5D coordinates to avoid rounding errors.
226           These are in units of edge length. */
227        int         fived[5];
228        /* This is used to quickly check if a vertex is visible. */
229        unsigned char off_screen;
230} fringe_node_c;
231
232typedef struct {
233        fringe_node_c *nodes;
234        /* This does not count off-screen nodes. */
235        int         n_nodes;
236} fringe_c;
237
238
239/*-
240 * The forced vertex pool contains vertices where at least one
241 * side of the tiled region can only be extended in one way.  Note
242 * that this does not necessarily mean that there would only be one
243 * applicable rule.  forced_sides are specified using S_LEFT and
244 * S_RIGHT as if looking at the untiled region from the vertex.
245 */
246struct forced_node {
247        fringe_node_c *vertex;
248        unsigned    forced_sides;
249        struct forced_node *next;
250};
251
252typedef struct {
253        forced_node_c *first;
254        int         n_nodes, n_visible;
255} forced_pool_c;
256
257
258/* This is the data related to the tiling of one screen. */
259typedef struct {
260        int         width, height;
261        XPoint      origin;
262        int         edge_length;
263        fringe_c    fringe;
264        forced_pool_c forced;
265        int         done, failures;
266        unsigned long thick_color, thin_color;
267        int         busyLoop;
268        Bool        ammann;
269} tiling_c;
270
271static tiling_c *tilings = (tiling_c *) NULL;
272
273/* The tiles are listed in counterclockwise order. */
274typedef struct {
275        vertex_type_c tiles[MAX_TILES_PER_VERTEX];
276        int         n_tiles;
277} vertex_rule_c;
278
279static vertex_rule_c vertex_rules[N_VERTEX_RULES] =
280{
281        {
282  {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2}, 5},
283        {
284  {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0}, 5},
285        {
286                {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THIN | 0}, 4},
287        {
288         {VT_THICK | 2, VT_THICK | 2, VT_THIN | 1, VT_THIN | 3, VT_THICK | 2,
289          VT_THIN | 1, VT_THIN | 3}, 7},
290        {
291                {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2,
292                 VT_THIN | 1, VT_THIN | 3}, 6},
293        {
294                {VT_THICK | 1, VT_THICK | 3, VT_THIN | 2}, 3},
295        {
296                {VT_THICK | 0, VT_THIN | 0, VT_THIN | 0}, 3},
297        {
298     {VT_THICK | 2, VT_THIN | 1, VT_THICK | 3, VT_THICK | 1, VT_THIN | 3}, 5}
299};
300
301
302/* Match information returned by match_rules. */
303typedef struct {
304        int         rule;
305        int         pos;
306} rule_match_c;
307
308
309/* Occasionally floating point coordinates are needed. */
310typedef struct {
311        float       x, y;
312} fcoord_c;
313
314
315/* All angles are measured in multiples of 36 degrees. */
316typedef int angle_c;
317
318static angle_c vtype_angles[] =
319{4, 1, 4, 1, 2, 3, 2, 3};
320
321#define vtype_angle( v) (vtype_angles[ v])
322
323
324/* Direction angle of an edge. */
325static      angle_c
326vertex_dir(ModeInfo * mi, fringe_node_c * vertex, unsigned side)
327{
328        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
329        fringe_node_c *v2 =
330        (side == S_LEFT ? vertex->next : vertex->prev);
331        register int i;
332
333        for (i = 0; i < 5; i++)
334                switch (v2->fived[i] - vertex->fived[i]) {
335                        case 1:
336                                return 2 * i;
337                        case -1:
338                                return (2 * i + 5) % 10;
339                }
340        tp->done = True;
341        if (MI_IS_VERBOSE(mi)) {
342                (void) fprintf(stderr,
343                       "Weirdness in vertex_dir (this has been reported)\n");
344                for (i = 0; i < 5; i++)
345                        (void) fprintf(stderr, "v2->fived[%d]=%d, vertex->fived[%d]=%d\n",
346                                       i, v2->fived[i], i, vertex->fived[i]);
347        }
348        tp->busyLoop = CELEBRATE;
349        return 0;
350}
351
352
353/* Move one step to a given direction. */
354static void
355add_unit_vec(angle_c dir, int *fived)
356{
357        static int  dir2i[] =
358        {0, 3, 1, 4, 2};
359
360        while (dir < 0)
361                dir += 10;
362        fived[dir2i[dir % 5]] += (dir % 2 ? -1 : 1);
363}
364
365
366/* For comparing coordinates. */
367#define fived_equal( f1, f2) (!memcmp( (f1), (f2), 5 * sizeof( int)))
368
369
370/*-
371 * This computes screen coordinates from 5D representation.  Note that X
372 * uses left-handed coordinates (y increases downwards).
373 */
374static void
375fived_to_loc(int fived[], tiling_c * tp, XPoint *pt)
376{
377        static fcoord_c fived_table[5] =
378        {
379                {.0, .0}};
380        float       fifth = 8 * atan(1.) / 5;
381        register int i;
382        register float r;
383        register fcoord_c offset;
384
385        *pt = tp->origin;
386        offset.x = 0.0;
387        offset.y = 0.0;
388        if (fived_table[0].x == .0)
389                for (i = 0; i < 5; i++) {
390                        fived_table[i].x = cos(fifth * i);
391                        fived_table[i].y = sin(fifth * i);
392                }
393        for (i = 0; i < 5; i++) {
394                r = fived[i] * tp->edge_length;
395                offset.x += r * fived_table[i].x;
396                offset.y -= r * fived_table[i].y;
397        }
398        (*pt).x += (int) (offset.x + .5);
399        (*pt).y += (int) (offset.y + .5);
400}
401
402
403/* Mop up dynamic data for one screen. */
404static void
405free_penrose(tiling_c * tp)
406{
407        register fringe_node_c *fp1, *fp2;
408        register forced_node_c *lp1, *lp2;
409
410        if (tp->fringe.nodes == NULL)
411                return;
412        fp1 = tp->fringe.nodes;
413        do {
414                fp2 = fp1;
415                fp1 = fp1->next;
416                (void) free((void *) fp2);
417        } while (fp1 != tp->fringe.nodes);
418        tp->fringe.nodes = (fringe_node_c *) NULL;
419        for (lp1 = tp->forced.first; lp1 != 0;) {
420                lp2 = lp1;
421                lp1 = lp1->next;
422                (void) free((void *) lp2);
423        }
424        tp->forced.first = 0;
425}
426
427
428/* Called to init the mode. */
429void
430init_penrose(ModeInfo * mi)
431{
432        tiling_c   *tp;
433        fringe_node_c *fp;
434        int         i, size;
435
436        if (tilings == NULL) {
437                if ((tilings = (tiling_c *) calloc(MI_NUM_SCREENS(mi),
438                                                 sizeof (tiling_c))) == NULL)
439                        return;
440        }
441        tp = &tilings[MI_SCREEN(mi)];
442
443#if 0 /* if you do this, then the -ammann and -no-ammann options don't work.
444         -- jwz */
445        if (MI_IS_FULLRANDOM(mi))
446                tp->ammann = (Bool) (LRAND() & 1);
447        else
448#endif /* 0 */
449                tp->ammann = ammann;
450
451        tp->done = False;
452        tp->busyLoop = 0;
453        tp->failures = 0;
454        tp->width = MI_WIDTH(mi);
455        tp->height = MI_HEIGHT(mi);
456        if (MI_NPIXELS(mi) > 2) {
457                tp->thick_color = NRAND(MI_NPIXELS(mi));
458                /* Insure good contrast */
459                tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color +
460                                  MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
461        }
462        size = MI_SIZE(mi);
463        if (size < -MINSIZE)
464                tp->edge_length = NRAND(MIN(-size, MAX(MINSIZE,
465                   MIN(tp->width, tp->height) / 2)) - MINSIZE + 1) + MINSIZE;
466        else if (size < MINSIZE) {
467                if (!size)
468                        tp->edge_length = MAX(MINSIZE, MIN(tp->width, tp->height) / 2);
469                else
470                        tp->edge_length = MINSIZE;
471        } else
472                tp->edge_length = MIN(size, MAX(MINSIZE,
473                                            MIN(tp->width, tp->height) / 2));
474        tp->origin.x = (tp->width / 2 + NRAND(tp->width)) / 2;
475        tp->origin.y = (tp->height / 2 + NRAND(tp->height)) / 2;
476        tp->fringe.n_nodes = 2;
477        if (tp->fringe.nodes != NULL)
478                free_penrose(tp);
479        if (tp->fringe.nodes != NULL || tp->forced.first != 0) {
480                if (MI_IS_VERBOSE(mi)) {
481                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
482                        (void) fprintf(stderr, "tp->fringe.nodes = NULL && tp->forced.first = 0\n");
483                }
484                free_penrose(tp);       /* Try again */
485                tp->done = True;
486        }
487        tp->forced.n_nodes = tp->forced.n_visible = 0;
488        if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) {
489                free_penrose(tp);
490                return;
491        }
492        if (fp == 0) {
493                if (MI_IS_VERBOSE(mi)) {
494                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
495                        (void) fprintf(stderr, "fp = 0\n");
496                }
497                if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) {
498                        free_penrose(tp);
499                        return;
500                }
501                tp->done = True;
502        }
503        /* First vertex. */
504        fp->rule_mask = (1 << N_VERTEX_RULES) - 1;
505        fp->list_ptr = 0;
506        if  ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) {
507                free_penrose(tp);
508                return;
509        }
510        if (fp->next == 0) {
511                if (MI_IS_VERBOSE(mi)) {
512                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
513                        (void) fprintf(stderr, "fp->next = 0\n");
514                }
515                if ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) {
516                        free_penrose(tp);
517                        return;
518                }
519                tp->done = True;
520        }
521        fp->n_tiles = 0;
522        fp->loc = tp->origin;
523        fp->off_screen = False;
524        for (i = 0; i < 5; i++)
525                fp->fived[i] = 0;
526
527        /* Second vertex. */
528        *(fp->next) = *fp;
529        fp->next->prev = fp->next->next = fp;
530        fp = fp->next;
531        i = NRAND(5);
532        fp->fived[i] = 2 * NRAND(2) - 1;
533        fived_to_loc(fp->fived, tp, &(fp->loc));
534        /* That's it!  We have created our first edge. */
535}
536
537/*-
538 * This attempts to match the configuration of vertex with the vertex
539 * rules.   The return value is a total match count.  If matches is
540 * non-null, it will be used to store information about the matches
541 * and must be large enough to contain it.  To play it absolutely
542 * safe, allocate room for MAX_TILES_PER_VERTEX * N_VERTEX_RULES
543 * entries when searching all matches.   The rule mask of vertex will
544 * be applied and rules masked out will not be searched.  Only strict
545 * subsequences match.  If first_only is true, the search stops when
546 * the first match is found.  Otherwise all matches will be found and
547 * the rule_mask of vertex will be updated, which also happens in
548 * single-match mode if no match is found.
549 */
550static int
551match_rules(fringe_node_c * vertex, rule_match_c * matches, int first_only)
552{
553        /* I will assume that I can fit all the relevant bits in vertex->tiles
554           into one unsigned long.  With 3 bits per element and at most 7
555           elements this means 21 bits, which should leave plenty of room.
556           After packing the bits the rest is just integer comparisons and
557           some bit shuffling.  This is essentially Rabin-Karp without
558           congruence arithmetic. */
559        register int i, j;
560        int         hits = 0, good_rules[N_VERTEX_RULES], n_good = 0;
561        unsigned long
562                    vertex_hash = 0, lower_bits_mask = ~(VT_TOTAL_MASK << VT_BITS * (vertex->n_tiles - 1));
563        unsigned    new_rule_mask = 0;
564
565        for (i = 0; i < N_VERTEX_RULES; i++)
566                if (vertex->n_tiles >= vertex_rules[i].n_tiles)
567                        vertex->rule_mask &= ~(1 << i);
568                else if (vertex->rule_mask & 1 << i)
569                        good_rules[n_good++] = i;
570        for (i = 0; i < vertex->n_tiles; i++)
571                vertex_hash |= (unsigned long) vertex->tiles[i] << (VT_BITS * i);
572
573        for (j = 0; j < n_good; j++) {
574                unsigned long rule_hash = 0;
575                vertex_rule_c *vr = vertex_rules + good_rules[j];
576
577                for (i = 0; i < vertex->n_tiles; i++)
578                        rule_hash |= (unsigned long) vr->tiles[i] << (VT_BITS * i);
579                if (rule_hash == vertex_hash) {
580                        if (matches != 0) {
581                                matches[hits].rule = good_rules[j];
582                                matches[hits].pos = 0;
583                        }
584                        hits++;
585                        if (first_only)
586                                return hits;
587                        else
588                                new_rule_mask |= 1 << good_rules[j];
589                }
590                for (i = vr->n_tiles - 1; i > 0; i--) {
591                        rule_hash = vr->tiles[i] | (rule_hash & lower_bits_mask) << VT_BITS;
592                        if (vertex_hash == rule_hash) {
593                                if (matches != 0) {
594                                        matches[hits].rule = good_rules[j];
595                                        matches[hits].pos = i;
596                                }
597                                hits++;
598                                if (first_only)
599                                        return hits;
600                                else
601                                        new_rule_mask |= 1 << good_rules[j];
602                        }
603                }
604        }
605        vertex->rule_mask = new_rule_mask;
606        return hits;
607}
608
609
610/*-
611 * find_completions finds the possible ways to add a tile to a vertex.
612 * The return values is the number of such possibilities.  You must
613 * first call match_rules to produce matches and n_matches.  sides
614 * specifies which side of the vertex to extend and can be S_LEFT or
615 * S_RIGHT.  If results is non-null, it should point to an array large
616 * enough to contain the results, which will be stored there.
617 * MAX_COMPL elements will always suffice.  If first_only is true we
618 * stop as soon as we find one possibility (NOT USED).
619 */
620#define MAX_COMPL 2
621
622static int
623find_completions(fringe_node_c * vertex, rule_match_c * matches, int n_matches,
624               unsigned side, vertex_type_c * results /*, int first_only */ )
625{
626        int         n_res = 0, cont;
627        register int i, j;
628        vertex_type_c buf[MAX_COMPL];
629
630        if (results == 0)
631                results = buf;
632        if (n_matches <= 0)
633                return 0;
634        for (i = 0; i < n_matches; i++) {
635                vertex_rule_c *rule = vertex_rules + matches[i].rule;
636                int         pos = (matches[i].pos
637                   + (side == S_RIGHT ? vertex->n_tiles : rule->n_tiles - 1))
638                % rule->n_tiles;
639                vertex_type_c vtype = rule->tiles[pos];
640
641                cont = 1;
642                for (j = 0; j < n_res; j++)
643                        if (vtype == results[j]) {
644                                cont = 0;
645                                break;
646                        }
647                if (cont)
648                        results[n_res++] = vtype;
649        }
650        return n_res;
651}
652
653
654/*-
655 * Draw a tile on the display.  Vertices must be given in a
656 * counterclockwise order.  vtype is the vertex type of v1 (and thus
657 * also gives the tile type).
658 */
659static void
660draw_tile(fringe_node_c * v1, fringe_node_c * v2,
661          fringe_node_c * v3, fringe_node_c * v4,
662          vertex_type_c vtype, ModeInfo * mi)
663{
664        Display    *display = MI_DISPLAY(mi);
665        Window      window = MI_WINDOW(mi);
666        GC          gc = MI_GC(mi);
667        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
668        XPoint      pts[5];
669        vertex_type_c corner = vtype & VT_CORNER_MASK;
670
671        if (v1->off_screen && v2->off_screen && v3->off_screen && v4->off_screen)
672                return;
673        pts[corner] = v1->loc;
674        pts[VT_RIGHT(corner)] = v2->loc;
675        pts[VT_FAR(corner)] = v3->loc;
676        pts[VT_LEFT(corner)] = v4->loc;
677        pts[4] = pts[0];
678        if (MI_NPIXELS(mi) > 2) {
679                if ((vtype & VT_TYPE_MASK) == VT_THICK)
680                        XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color));
681                else
682                        XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
683        } else
684                XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
685        XFillPolygon(display, window, gc, pts, 4, Convex, CoordModeOrigin);
686        XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
687        XDrawLines(display, window, gc, pts, 5, CoordModeOrigin);
688
689        if (tp->ammann) {
690                /* Draw some Ammann lines for debugging purposes.  This will probably
691                   fail miserably on a b&w display. */
692
693                if ((vtype & VT_TYPE_MASK) == VT_THICK) {
694                        static float r = .0;
695
696                        if (r == .0) {
697                                float       pi10 = 2 * atan(1.) / 5;
698
699                                r = 1 - sin(pi10) / (2 * sin(3 * pi10));
700                        }
701                        if (MI_NPIXELS(mi) > 2)
702                                XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
703                        else {
704                                XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
705                                XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
706                        }
707                        XDrawLine(display, window, gc,
708                              (int) (r * pts[3].x + (1 - r) * pts[0].x + .5),
709                              (int) (r * pts[3].y + (1 - r) * pts[0].y + .5),
710                              (int) (r * pts[1].x + (1 - r) * pts[0].x + .5),
711                             (int) (r * pts[1].y + (1 - r) * pts[0].y + .5));
712                        if (MI_NPIXELS(mi) <= 2)
713                                XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter);
714                } else {
715                        if (MI_NPIXELS(mi) > 2)
716                                XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color));
717                        else {
718                                XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
719                                XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
720                        }
721                        XDrawLine(display, window, gc,
722                                  (int) ((pts[3].x + pts[2].x) / 2 + .5),
723                                  (int) ((pts[3].y + pts[2].y) / 2 + .5),
724                                  (int) ((pts[1].x + pts[2].x) / 2 + .5),
725                                  (int) ((pts[1].y + pts[2].y) / 2 + .5));
726                        if (MI_NPIXELS(mi) <= 2)
727                                XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter);
728                }
729        }
730}
731
732/*-
733 * Update the status of this vertex on the forced vertex queue.  If
734 * the vertex has become untileable set tp->done.  This is supposed
735 * to detect dislocations -- never call this routine with a completely
736 * tiled vertex.
737 *
738 * Check for untileable vertices in check_vertex and stop tiling as
739 * soon as one finds one.  I don't know if it is possible to run out
740 * of forced vertices while untileable vertices exist (or will
741 * cavities inevitably appear).  If this can happen, add_random_tile
742 * might get called with an untileable vertex, causing ( n <= 1).
743 * (This is what the tp->done checks for).
744 *
745 * A delayLoop celebrates the dislocation.
746 */
747static void
748check_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp)
749{
750        rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
751        int         n_hits = match_rules(vertex, hits, False);
752        unsigned    forced_sides = 0;
753
754        if (vertex->rule_mask == 0) {
755                tp->done = True;
756                if (MI_IS_VERBOSE(mi)) {
757                        (void) fprintf(stderr, "Dislocation occurred!\n");
758                }
759                tp->busyLoop = CELEBRATE;       /* Should be able to recover */
760        }
761        if (1 == find_completions(vertex, hits, n_hits, S_LEFT, 0 /*, False */ ))
762                forced_sides |= S_LEFT;
763        if (1 == find_completions(vertex, hits, n_hits, S_RIGHT, 0 /*, False */ ))
764                forced_sides |= S_RIGHT;
765        if (forced_sides == 0) {
766                if (vertex->list_ptr != 0) {
767                        forced_node_c *node = *vertex->list_ptr;
768
769                        *vertex->list_ptr = node->next;
770                        if (node->next != 0)
771                                node->next->vertex->list_ptr = vertex->list_ptr;
772                        (void) free((void *) node);
773                        tp->forced.n_nodes--;
774                        if (!vertex->off_screen)
775                                tp->forced.n_visible--;
776                        vertex->list_ptr = 0;
777                }
778        } else {
779                forced_node_c *node;
780
781                if (vertex->list_ptr == 0) {
782                        if ((node = ALLOC_NODE(forced_node_c)) == NULL)
783                                return;
784                        node->vertex = vertex;
785                        node->next = tp->forced.first;
786                        if (tp->forced.first != 0)
787                                tp->forced.first->vertex->list_ptr = &(node->next);
788                        tp->forced.first = node;
789                        vertex->list_ptr = &(tp->forced.first);
790                        tp->forced.n_nodes++;
791                        if (!vertex->off_screen)
792                                tp->forced.n_visible++;
793                } else
794                        node = *vertex->list_ptr;
795                node->forced_sides = forced_sides;
796        }
797}
798
799
800/*-
801 * Delete this vertex.  If the vertex is a member of the forced vertex queue,
802 * also remove that entry.  We assume that the vertex is no longer
803 * connected to the fringe.  Note that tp->fringe.nodes must not point to
804 * the vertex being deleted.
805 */
806static void
807delete_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp)
808{
809        if (tp->fringe.nodes == vertex) {
810                tp->done = True;
811                if (MI_IS_VERBOSE(mi)) {
812                        (void) fprintf(stderr, "Weirdness in delete_penrose()\n");
813                        (void) fprintf(stderr, "tp->fringe.nodes == vertex\n");
814                }
815                tp->busyLoop = CELEBRATE;
816        }
817        if (vertex->list_ptr != 0) {
818                forced_node_c *node = *vertex->list_ptr;
819
820                *vertex->list_ptr = node->next;
821                if (node->next != 0)
822                        node->next->vertex->list_ptr = vertex->list_ptr;
823                (void) free((void *) node);
824                tp->forced.n_nodes--;
825                if (!vertex->off_screen)
826                        tp->forced.n_visible--;
827        }
828        if (!vertex->off_screen)
829                tp->fringe.n_nodes--;
830        (void) free((void *) vertex);
831}
832
833
834/*-
835 * Check whether the addition of a tile of type vtype would completely fill
836 * the space available at vertex.
837 */
838static int
839fills_vertex(ModeInfo * mi, vertex_type_c vtype, fringe_node_c * vertex)
840{
841        return
842                (vertex_dir(mi, vertex, S_LEFT) - vertex_dir(mi, vertex, S_RIGHT)
843                 - vtype_angle(vtype)) % 10 == 0;
844}
845
846
847/*-
848 * If you were to add a tile of type vtype to a specified side of
849 * vertex, fringe_changes tells you which other vertices it would
850 * attach to.  The addresses of these vertices will be stored in the
851 * last three arguments.  Null is stored if the corresponding vertex
852 * would need to be allocated.
853 *
854 * The function also analyzes which vertices would be swallowed by the tiling
855 * and thus cut off from the fringe.  The result is returned as a bit pattern.
856 */
857#define FC_BAG 1                /* Total enclosure.  Should never occur. */
858#define FC_NEW_RIGHT 2
859#define FC_NEW_FAR 4
860#define FC_NEW_LEFT 8
861#define FC_NEW_MASK 0xe
862#define FC_CUT_THIS 0x10
863#define FC_CUT_RIGHT 0x20
864#define FC_CUT_FAR 0x40
865#define FC_CUT_LEFT 0x80
866#define FC_CUT_MASK 0xf0
867#define FC_TOTAL_MASK 0xff
868
869static unsigned
870fringe_changes(ModeInfo * mi, fringe_node_c * vertex,
871               unsigned side, vertex_type_c vtype,
872               fringe_node_c ** right, fringe_node_c ** far,
873               fringe_node_c ** left)
874{
875        fringe_node_c *v, *f = (fringe_node_c *) NULL;
876        unsigned    result = FC_NEW_FAR;        /* We clear this later if necessary. */
877
878        if (far)
879                *far = 0;
880        if (fills_vertex(mi, vtype, vertex)) {
881                result |= FC_CUT_THIS;
882        } else if (side == S_LEFT) {
883                result |= FC_NEW_RIGHT;
884                if (right)
885                        *right = 0;
886        } else {
887                result |= FC_NEW_LEFT;
888                if (left)
889                        *left = 0;
890        }
891
892        if (!(result & FC_NEW_LEFT)) {
893                v = vertex->next;
894                if (left)
895                        *left = v;
896                if (fills_vertex(mi, VT_LEFT(vtype), v)) {
897                        result = (result & ~FC_NEW_FAR) | FC_CUT_LEFT;
898                        f = v->next;
899                        if (far)
900                                *far = f;
901                }
902        }
903        if (!(result & FC_NEW_RIGHT)) {
904                v = vertex->prev;
905                if (right)
906                        *right = v;
907                if (fills_vertex(mi, VT_RIGHT(vtype), v)) {
908                        result = (result & ~FC_NEW_FAR) | FC_CUT_RIGHT;
909                        f = v->prev;
910                        if (far)
911                                *far = f;
912                }
913        }
914        if (!(result & FC_NEW_FAR)
915            && fills_vertex(mi, VT_FAR(vtype), f)) {
916                result |= FC_CUT_FAR;
917                result &= (~FC_NEW_LEFT & ~FC_NEW_RIGHT);
918                if (right && (result & FC_CUT_LEFT))
919                        *right = f->next;
920                if (left && (result & FC_CUT_RIGHT))
921                        *left = f->prev;
922        }
923        if (((result & FC_CUT_LEFT) && (result & FC_CUT_RIGHT))
924            || ((result & FC_CUT_THIS) && (result & FC_CUT_FAR)))
925                result |= FC_BAG;
926        return result;
927}
928
929
930/* A couple of lesser helper functions for add_tile. */
931static void
932add_vtype(fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
933{
934        if (side == S_RIGHT)
935                vertex->tiles[vertex->n_tiles++] = vtype;
936        else {
937                register int i;
938
939                for (i = vertex->n_tiles; i > 0; i--)
940                        vertex->tiles[i] = vertex->tiles[i - 1];
941                vertex->tiles[0] = vtype;
942                vertex->n_tiles++;
943        }
944}
945
946static fringe_node_c *
947alloc_vertex(ModeInfo * mi, angle_c dir, fringe_node_c * from, tiling_c * tp)
948{
949        fringe_node_c *v;
950
951        if ((v = ALLOC_NODE(fringe_node_c)) == NULL) {
952                tp->done = True;
953                if (MI_IS_VERBOSE(mi)) {
954                        (void) fprintf(stderr, "No memory in alloc_vertex()\n");
955                }
956                tp->busyLoop = CELEBRATE;
957                return v;
958        }
959        *v = *from;
960        add_unit_vec(dir, v->fived);
961        fived_to_loc(v->fived, tp, &(v->loc));
962        if (v->loc.x < 0 || v->loc.y < 0
963            || v->loc.x >= tp->width || v->loc.y >= tp->height) {
964                v->off_screen = True;
965                if (v->loc.x < -tp->width || v->loc.y < -tp->height
966                  || v->loc.x >= 2 * tp->width || v->loc.y >= 2 * tp->height)
967                        tp->done = True;
968        } else {
969                v->off_screen = False;
970                tp->fringe.n_nodes++;
971        }
972        v->n_tiles = 0;
973        v->rule_mask = (1 << N_VERTEX_RULES) - 1;
974        v->list_ptr = 0;
975        return v;
976}
977
978/*-
979 * Add a tile described by vtype to the side of vertex.  This must be
980 * allowed by the rules -- we do not check it here.  New vertices are
981 * allocated as necessary.  The fringe and the forced vertex pool are updated.
982 * The new tile is drawn on the display.
983 *
984 * One thing we do check here is whether the new tile causes an untiled
985 * area to become enclosed by the tiling.  If this would happen, the tile
986 * is not added.  The return value is true iff a tile was added.
987 */
988static int
989add_tile(ModeInfo * mi,
990         fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
991{
992        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
993
994        fringe_node_c
995                *left = (fringe_node_c *) NULL,
996                *right = (fringe_node_c *) NULL,
997                *far = (fringe_node_c *) NULL,
998                *node;
999        unsigned    fc = fringe_changes(mi, vertex, side, vtype, &right, &far, &left);
1000
1001        vertex_type_c
1002                ltype = VT_LEFT(vtype),
1003                rtype = VT_RIGHT(vtype),
1004                ftype = VT_FAR(vtype);
1005
1006        /* By our conventions vertex->next lies to the left of vertex and
1007           vertex->prev to the right. */
1008
1009        /* This should never occur. */
1010        if (fc & FC_BAG) {
1011                tp->done = True;
1012                if (MI_IS_VERBOSE(mi)) {
1013                        (void) fprintf(stderr, "Weirdness in add_tile()\n");
1014                        (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
1015                }
1016        }
1017        if (side == S_LEFT) {
1018                if (right == NULL)
1019                        if ((right = alloc_vertex(mi, vertex_dir(mi, vertex, S_LEFT) -
1020                                        vtype_angle(vtype), vertex, tp)) == NULL)
1021                                return False;
1022                if (far == NULL)
1023                        if ((far = alloc_vertex(mi, vertex_dir(mi, left, S_RIGHT) +
1024                                        vtype_angle(ltype), left, tp)) == NULL)
1025                                return False;
1026        } else {
1027                if (left == NULL)
1028                        if ((left = alloc_vertex(mi, vertex_dir(mi, vertex, S_RIGHT) +
1029                                        vtype_angle(vtype), vertex, tp)) == NULL)
1030                                return False;
1031                if (far == NULL)
1032                        if ((far = alloc_vertex(mi, vertex_dir(mi, right, S_LEFT) -
1033                                        vtype_angle(rtype), right, tp)) == NULL)
1034                                return False;
1035        }
1036
1037        /* Having allocated the new vertices, but before joining them with
1038           the rest of the fringe, check if vertices with same coordinates
1039           already exist.  If any such are found, give up. */
1040        node = tp->fringe.nodes;
1041        do {
1042                if (((fc & FC_NEW_LEFT) && fived_equal(node->fived, left->fived))
1043                    || ((fc & FC_NEW_RIGHT) && fived_equal(node->fived, right->fived))
1044                    || ((fc & FC_NEW_FAR) && fived_equal(node->fived, far->fived))) {
1045                        /* Better luck next time. */
1046                        if (fc & FC_NEW_LEFT)
1047                                delete_vertex(mi, left, tp);
1048                        if (fc & FC_NEW_RIGHT)
1049                                delete_vertex(mi, right, tp);
1050                        if (fc & FC_NEW_FAR)
1051                                delete_vertex(mi, far, tp);
1052                        return False;
1053                }
1054                node = node->next;
1055        } while (node != tp->fringe.nodes);
1056
1057        /* Rechain. */
1058        if (!(fc & FC_CUT_THIS)) {
1059                if (side == S_LEFT) {
1060                        vertex->next = right;
1061                        right->prev = vertex;
1062                } else {
1063                        vertex->prev = left;
1064                        left->next = vertex;
1065                }
1066        }
1067        if (!(fc & FC_CUT_FAR)) {
1068                if (!(fc & FC_CUT_LEFT)) {
1069                        far->next = left;
1070                        left->prev = far;
1071                }
1072                if (!(fc & FC_CUT_RIGHT)) {
1073                        far->prev = right;
1074                        right->next = far;
1075                }
1076        }
1077        draw_tile(vertex, right, far, left, vtype, mi);
1078
1079        /* Delete vertices that are no longer on the fringe.  Check the others. */
1080        if (fc & FC_CUT_THIS) {
1081                tp->fringe.nodes = far;
1082                delete_vertex(mi, vertex, tp);
1083        } else {
1084                add_vtype(vertex, side, vtype);
1085                check_vertex(mi, vertex, tp);
1086                tp->fringe.nodes = vertex;
1087        }
1088        if (fc & FC_CUT_FAR)
1089                delete_vertex(mi, far, tp);
1090        else {
1091                add_vtype(far, fc & FC_CUT_RIGHT ? S_LEFT : S_RIGHT, ftype);
1092                check_vertex(mi, far, tp);
1093        }
1094        if (fc & FC_CUT_LEFT)
1095                delete_vertex(mi, left, tp);
1096        else {
1097                add_vtype(left, fc & FC_CUT_FAR ? S_LEFT : S_RIGHT, ltype);
1098                check_vertex(mi, left, tp);
1099        }
1100        if (fc & FC_CUT_RIGHT)
1101                delete_vertex(mi, right, tp);
1102        else {
1103                add_vtype(right, fc & FC_CUT_FAR ? S_RIGHT : S_LEFT, rtype);
1104                check_vertex(mi, right, tp);
1105        }
1106        return True;
1107}
1108
1109
1110/*-
1111 * Add a forced tile to a given forced vertex.  Basically an easy job,
1112 * since we know what to add.  But it might fail if adding the tile
1113 * would cause some untiled area to become enclosed.  There is also another
1114 * more exotic culprit: we might have a dislocation.  Fortunately, they
1115 * are very rare (the PRL article reported that perfect tilings of over
1116 * 2^50 tiles had been generated).  There is a version of the algorithm
1117 * that doesn't produce dislocations, but it's a lot hairier than the
1118 * simpler version I used.
1119 */
1120static int
1121add_forced_tile(ModeInfo * mi, forced_node_c * node)
1122{
1123        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
1124        unsigned    side;
1125        vertex_type_c vtype;
1126        rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1127        int         n;
1128
1129        if (node->forced_sides == (S_LEFT | S_RIGHT))
1130                side = NRAND(2) ? S_LEFT : S_RIGHT;
1131        else
1132                side = node->forced_sides;
1133        n = match_rules(node->vertex, hits, True);
1134        n = find_completions(node->vertex, hits, n, side, &vtype /*, True */ );
1135        if (n <= 0) {
1136                tp->done = True;
1137                if (MI_IS_VERBOSE(mi)) {
1138                        (void) fprintf(stderr, "Weirdness in add_forced_tile()\n");
1139                        (void) fprintf(stderr, "n = %d\n", n);
1140                }
1141        }
1142        return add_tile(mi, node->vertex, side, vtype);
1143}
1144
1145
1146/*-
1147 * Whether the addition of a tile of vtype on the given side of vertex
1148 * would conform to the rules.  The efficient way to do this would be
1149 * to add the new tile and then use the same type of search as in
1150 * match_rules.  However, this function is not a performance
1151 * bottleneck (only needed for random tile additions, which are
1152 * relatively infrequent), so I will settle for a simpler implementation.
1153 */
1154static int
1155legal_move(fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
1156{
1157        rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1158        vertex_type_c legal_vt[MAX_COMPL];
1159        int         n_hits, n_legal, i;
1160
1161        n_hits = match_rules(vertex, hits, False);
1162        n_legal = find_completions(vertex, hits, n_hits, side, legal_vt /*, False */ );
1163        for (i = 0; i < n_legal; i++)
1164                if (legal_vt[i] == vtype)
1165                        return True;
1166        return False;
1167}
1168
1169
1170/*-
1171 * Add a randomly chosen tile to a given vertex.  This requires more checking
1172 * as we must make sure the new tile conforms to the vertex rules at every
1173 * vertex it touches. */
1174static void
1175add_random_tile(fringe_node_c * vertex, ModeInfo * mi)
1176{
1177        fringe_node_c *right, *left, *far;
1178        int         i, j, n, n_hits, n_good;
1179        unsigned    side, fc, no_good, s;
1180        vertex_type_c vtypes[MAX_COMPL];
1181        rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1182        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
1183
1184        if (MI_NPIXELS(mi) > 2) {
1185                tp->thick_color = NRAND(MI_NPIXELS(mi));
1186                /* Insure good contrast */
1187                tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color +
1188                                  MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
1189        } else
1190                tp->thick_color = tp->thin_color = MI_WHITE_PIXEL(mi);
1191        n_hits = match_rules(vertex, hits, False);
1192        side = NRAND(2) ? S_LEFT : S_RIGHT;
1193        n = find_completions(vertex, hits, n_hits, side, vtypes /*, False */ );
1194        /* One answer would mean a forced tile. */
1195        if (n <= 0) {
1196                tp->done = True;
1197                if (MI_IS_VERBOSE(mi)) {
1198                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1199                        (void) fprintf(stderr, "n = %d\n", n);
1200                }
1201        }
1202        no_good = 0;
1203        n_good = n;
1204        for (i = 0; i < n; i++) {
1205                fc = fringe_changes(mi, vertex, side, vtypes[i], &right, &far, &left);
1206                if (fc & FC_BAG) {
1207                        tp->done = True;
1208                        if (MI_IS_VERBOSE(mi)) {
1209                                (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1210                                (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
1211                        }
1212                }
1213                if (right) {
1214                        s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_LEFT)) ? S_RIGHT : S_LEFT);
1215                        if (!legal_move(right, s, VT_RIGHT(vtypes[i]))) {
1216                                no_good |= (1 << i);
1217                                n_good--;
1218                                continue;
1219                        }
1220                }
1221                if (left) {
1222                        s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_RIGHT)) ? S_LEFT : S_RIGHT);
1223                        if (!legal_move(left, s, VT_LEFT(vtypes[i]))) {
1224                                no_good |= (1 << i);
1225                                n_good--;
1226                                continue;
1227                        }
1228                }
1229                if (far) {
1230                        s = ((fc & FC_CUT_LEFT) ? S_RIGHT : S_LEFT);
1231                        if (!legal_move(far, s, VT_FAR(vtypes[i]))) {
1232                                no_good |= (1 << i);
1233                                n_good--;
1234                        }
1235                }
1236        }
1237        if (n_good <= 0) {
1238                tp->done = True;
1239                if (MI_IS_VERBOSE(mi)) {
1240                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1241                        (void) fprintf(stderr, "n_good = %d\n", n_good);
1242                }
1243        }
1244        n = NRAND(n_good);
1245        for (i = j = 0; i <= n; i++, j++)
1246                while (no_good & (1 << j))
1247                        j++;
1248
1249        if (!add_tile(mi, vertex, side, vtypes[j - 1])) {
1250                tp->done = True;
1251                if (MI_IS_VERBOSE(mi)) {
1252                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1253                }
1254                free_penrose(tp);
1255        }
1256}
1257
1258/* One step of the growth algorithm. */
1259void
1260draw_penrose(ModeInfo * mi)
1261{
1262        int         i = 0, n;
1263        forced_node_c *p;
1264        tiling_c   *tp;
1265
1266        if (tilings == NULL)
1267                return;
1268        tp = &tilings[MI_SCREEN(mi)];
1269        if (tp->fringe.nodes == NULL)
1270                return;
1271
1272        MI_IS_DRAWN(mi) = True;
1273        p = tp->forced.first;
1274        if (tp->busyLoop > 0) {
1275                tp->busyLoop--;
1276                return;
1277        }
1278        if (tp->done || tp->failures >= 100) {
1279                init_penrose(mi);
1280                return;
1281        }
1282        /* Check for the initial "2-gon". */
1283        if (tp->fringe.nodes->prev == tp->fringe.nodes->next) {
1284                vertex_type_c vtype = (unsigned char) (VT_TOTAL_MASK & LRAND());
1285
1286                MI_CLEARWINDOW(mi);
1287
1288                if (!add_tile(mi, tp->fringe.nodes, S_LEFT, vtype))
1289                        free_penrose(tp);
1290                return;
1291        }
1292        /* No visible nodes left. */
1293        if (tp->fringe.n_nodes == 0) {
1294                tp->done = True;
1295                tp->busyLoop = COMPLETION;      /* Just finished drawing */
1296                return;
1297        }
1298        if (tp->forced.n_visible > 0 && tp->failures < 10) {
1299                n = NRAND(tp->forced.n_visible);
1300                for (;;) {
1301                        while (p->vertex->off_screen)
1302                                p = p->next;
1303                        if (i++ < n)
1304                                p = p->next;
1305                        else
1306                                break;
1307                }
1308        } else if (tp->forced.n_nodes > 0) {
1309                n = NRAND(tp->forced.n_nodes);
1310                while (i++ < n)
1311                        p = p->next;
1312        } else {
1313                fringe_node_c *fringe_p = tp->fringe.nodes;
1314
1315                n = NRAND(tp->fringe.n_nodes);
1316                i = 0;
1317                for (; i <= n; i++)
1318                        do {
1319                                fringe_p = fringe_p->next;
1320                        } while (fringe_p->off_screen);
1321                add_random_tile(fringe_p, mi);
1322                tp->failures = 0;
1323                return;
1324        }
1325        if (add_forced_tile(mi, p))
1326                tp->failures = 0;
1327        else
1328                tp->failures++;
1329}
1330
1331
1332/* Total clean-up. */
1333void
1334release_penrose(ModeInfo * mi)
1335{
1336        if (tilings != NULL) {
1337                int         screen;
1338
1339                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1340                        free_penrose(&tilings[screen]);
1341                (void) free((void *) tilings);
1342                tilings = (tiling_c *) NULL;
1343        }
1344}
1345
1346#endif /* MODE_penrose */
Note: See TracBrowser for help on using the repository browser.