~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper-updates

« back to all changes in this revision

Viewing changes to hacks/penrose.c

  • Committer: Bazaar Package Importer
  • Author(s): Ralf Hildebrandt
  • Date: 2005-04-09 00:06:43 UTC
  • mfrom: (1.1.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050409000643-z0abtifbt9s20pcc
Tags: 4.21-3
Patch by Joachim Breitner to check more frequently if DPMS kicked in (closes: #303374, #286664).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 4 -*-
2
 
 * penrose --- quasiperiodic tilings.
3
 
 */
 
1
/* -*- Mode: C; tab-width: 4 -*- */
 
2
/* penrose --- quasiperiodic tilings */
4
3
 
5
4
/*  As reported in News of the Weird:
6
5
 
19
18
                                http://www.nine.org/notw/notw.html
20
19
 */
21
20
 
22
 
 
23
 
#if !defined( lint ) && !defined( SABER )
24
 
static const char sccsid[] = "@(#)penrose.c     4.00 97/01/01 xlockmore";
 
21
#if 0
 
22
static const char sccsid[] = "@(#)penrose.c     5.00 2000/11/01 xlockmore";
25
23
#endif
26
24
 
27
 
/* Copyright (c) 1996 by Timo Korvola <tkorvola@dopey.hut.fi>
 
25
/*-
 
26
 * Copyright (c) 1996 by Timo Korvola <tkorvola@dopey.hut.fi>
28
27
 *
29
28
 * Permission to use, copy, modify, and distribute this software and its
30
29
 * documentation for any purpose and without fee is hereby granted,
39
38
 * other special, indirect and consequential damages.
40
39
 *
41
40
 * Revision History:
42
 
 * 10-May-97: jwz@jwz.org: turned into a standalone program.
43
 
 * 09-Sep-96: Written.  */
 
41
 * 01-Nov-2000: Allocation checks
 
42
 * 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
 
43
 * 09-Sep-1996: Written.
 
44
 */
44
45
 
45
46
/*-
46
47
Be careful, this probably still has a few bugs (many of which may only
63
64
 * untiled area.  Whenever this is in danger of happening, we just
64
65
 * do not add the tile, hoping for a better random choice the next
65
66
 * time.  Second, when choosing a vertex randomly, we will take
66
 
 * one that lies withing the viewport if available.  If this seems to
 
67
 * one that lies within the viewport if available.  If this seems to
67
68
 * cause enclosures in the forced rule case, we will allow invisible
68
69
 * vertices to be chosen.
69
70
 *
73
74
 * horizontally or vertically or forced rule choice has failed 100
74
75
 * times due to areas about to become enclosed.
75
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
 *
76
82
 */
77
83
 
78
84
#ifdef STANDALONE
79
 
# define PROGCLASS                                      "Penrose"
80
 
# define HACK_INIT                                      init_penrose
81
 
# define HACK_DRAW                                      draw_penrose
82
 
# define penrose_opts                           xlockmore_opts
83
 
# define DEFAULTS       "*delay:                10000 \n"                       \
84
 
                                        "*size:                 40    \n"                       \
85
 
                                        "*ncolors:              64   \n"
86
 
# include "xlockmore.h"                         /* from the xscreensaver distribution */
87
 
#else  /* !STANDALONE */
88
 
# include "xlock.h"                                     /* from the xlockmore distribution */
 
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 */
89
96
#endif /* !STANDALONE */
90
97
 
 
98
#ifdef MODE_penrose
 
99
 
 
100
#define DEF_AMMANN  "False"
 
101
 
 
102
static Bool ammann;
 
103
 
 
104
static XrmOptionDescRec opts[] =
 
105
{
 
106
        {"-ammann", ".penrose.ammann", XrmoptionNoArg, "on"},
 
107
        {"+ammann", ".penrose.ammann", XrmoptionNoArg, "off"}
 
108
};
 
109
static argtype vars[] =
 
110
{
 
111
        {&ammann, "ammann", "Ammann", DEF_AMMANN, t_Bool}
 
112
};
 
113
static OptionStruct desc[] =
 
114
{
 
115
        {"-/+ammann", "turn on/off Ammann lines"}
 
116
};
 
117
 
 
118
ModeSpecOpt penrose_opts =
 
119
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
 
120
 
 
121
#ifdef USE_MODULES
 
122
ModStruct   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
91
129
 
92
130
/*-
93
131
 * Annoyingly the ANSI C library people have reserved all identifiers
102
140
 * vertex rules only allow at most seven tiles to meet at a vertex.
103
141
 */
104
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
 
105
146
#define MAX_TILES_PER_VERTEX 7
106
147
#define N_VERTEX_RULES 8
107
 
#define ALLOC_NODE( type) ((type *)malloc( sizeof( type)))
108
 
#define DEF_AMMANN  "False"
109
 
 
110
 
static Bool ammann;
111
 
 
112
 
/* How long in seconds should we wait before starting a new tiling? */
113
 
static long redo_delay = 3;
114
 
static long redo_delay_usec;
115
 
 
116
 
static XrmOptionDescRec opts[] =
117
 
{
118
 
        {"-ammann", ".penrose.ammann", XrmoptionNoArg, (caddr_t) "on"},
119
 
        {"+ammann", ".penrose.ammann", XrmoptionNoArg, (caddr_t) "off"},
120
 
        {"-redoDelay", ".penrose.redoDelay", XrmoptionSepArg, NULL}
121
 
};
122
 
static argtype vars[] =
123
 
{
124
 
        {(caddr_t *) & ammann, "ammann", "Ammann", DEF_AMMANN, t_Bool},
125
 
        {(caddr_t *) & redo_delay, "redoDelay", "RedoDelay", "3", t_Int}
126
 
};
127
 
static OptionStruct desc[] =
128
 
{
129
 
        {"-/+ammann", "turn on/off Ammann lines"},
130
 
        {"-redoDelay", "delay between new tilings"}
131
 
};
132
 
 
133
 
ModeSpecOpt penrose_opts = { 3, opts, 2, vars, desc };
134
 
 
 
148
#define ALLOC_NODE(type) (type *)malloc(sizeof (type))
135
149
 
136
150
/*-
137
151
 * These are used to specify directions.  They can also be used in bit
180
194
 * to fill.
181
195
 *
182
196
 * Here we use a doubly chained ring-like structure as vertices often need
183
 
 * to be removed or inserted (they are kept in geometrical order 
 
197
 * to be removed or inserted (they are kept in geometrical order
184
198
 * circling the tiled area counterclockwise).  The ring is refered to by
185
199
 * a pointer to one more or less random node.  When deleting nodes one
186
200
 * must make sure that this pointer continues to refer to a valid
249
263
        fringe_c    fringe;
250
264
        forced_pool_c forced;
251
265
        int         done, failures;
252
 
        int         thick_color, thin_color;
 
266
        unsigned long thick_color, thin_color;
 
267
        int         busyLoop;
 
268
        Bool        ammann;
253
269
} tiling_c;
254
270
 
255
 
static tiling_c *tilings;       /* = {0} */
256
 
 
 
271
static tiling_c *tilings = (tiling_c *) NULL;
257
272
 
258
273
/* The tiles are listed in counterclockwise order. */
259
274
typedef struct {
323
338
                                return (2 * i + 5) % 10;
324
339
                }
325
340
        tp->done = True;
326
 
        if (MI_WIN_IS_VERBOSE(mi)) {
 
341
        if (MI_IS_VERBOSE(mi)) {
327
342
                (void) fprintf(stderr,
328
 
                   "Weirdness in vertex_dir (this has been reported)\n");
 
343
                       "Weirdness in vertex_dir (this has been reported)\n");
329
344
                for (i = 0; i < 5; i++)
330
345
                        (void) fprintf(stderr, "v2->fived[%d]=%d, vertex->fived[%d]=%d\n",
331
 
                                      i, v2->fived[i], i, vertex->fived[i]);
 
346
                                       i, v2->fived[i], i, vertex->fived[i]);
332
347
        }
333
 
        MI_PAUSE(mi) = redo_delay_usec;
 
348
        tp->busyLoop = CELEBRATE;
334
349
        return 0;
335
350
}
336
351
 
356
371
 * This computes screen coordinates from 5D representation.  Note that X
357
372
 * uses left-handed coordinates (y increases downwards).
358
373
 */
359
 
static      XPoint
360
 
fived_to_loc(int fived[], tiling_c * tp)
 
374
static void
 
375
fived_to_loc(int fived[], tiling_c * tp, XPoint *pt)
361
376
{
362
377
        static fcoord_c fived_table[5] =
363
378
        {
365
380
        float       fifth = 8 * atan(1.) / 5;
366
381
        register int i;
367
382
        register float r;
368
 
        register fcoord_c offset =
369
 
        {.0, .0};
370
 
        XPoint      pt = tp->origin;
 
383
        register fcoord_c offset;
371
384
 
 
385
        *pt = tp->origin;
 
386
        offset.x = 0.0;
 
387
        offset.y = 0.0;
372
388
        if (fived_table[0].x == .0)
373
389
                for (i = 0; i < 5; i++) {
374
390
                        fived_table[i].x = cos(fifth * i);
379
395
                offset.x += r * fived_table[i].x;
380
396
                offset.y -= r * fived_table[i].y;
381
397
        }
382
 
        pt.x += (int) (offset.x + .5);
383
 
        pt.y += (int) (offset.y + .5);
384
 
        return pt;
 
398
        (*pt).x += (int) (offset.x + .5);
 
399
        (*pt).y += (int) (offset.y + .5);
385
400
}
386
401
 
387
402
 
388
403
/* Mop up dynamic data for one screen. */
389
404
static void
390
 
release_screen(tiling_c * tp)
 
405
free_penrose(tiling_c * tp)
391
406
{
392
407
        register fringe_node_c *fp1, *fp2;
393
408
        register forced_node_c *lp1, *lp2;
394
409
 
395
 
        if (tp->fringe.nodes == 0)
 
410
        if (tp->fringe.nodes == NULL)
396
411
                return;
397
412
        fp1 = tp->fringe.nodes;
398
413
        do {
399
414
                fp2 = fp1;
400
415
                fp1 = fp1->next;
401
 
                (void) free((char *) fp2);
 
416
                (void) free((void *) fp2);
402
417
        } while (fp1 != tp->fringe.nodes);
403
 
        tp->fringe.nodes = 0;
 
418
        tp->fringe.nodes = (fringe_node_c *) NULL;
404
419
        for (lp1 = tp->forced.first; lp1 != 0;) {
405
420
                lp2 = lp1;
406
421
                lp1 = lp1->next;
407
 
                (void) free((char *) lp2);
 
422
                (void) free((void *) lp2);
408
423
        }
409
424
        tp->forced.first = 0;
410
425
}
418
433
        fringe_node_c *fp;
419
434
        int         i, size;
420
435
 
421
 
        redo_delay_usec = redo_delay * 1000000;
422
 
 
423
436
        if (tilings == NULL) {
424
437
                if ((tilings = (tiling_c *) calloc(MI_NUM_SCREENS(mi),
425
438
                                                 sizeof (tiling_c))) == NULL)
426
439
                        return;
427
440
        }
428
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
 
429
451
        tp->done = False;
 
452
        tp->busyLoop = 0;
430
453
        tp->failures = 0;
431
 
        tp->width = MI_WIN_WIDTH(mi);
432
 
        tp->height = MI_WIN_HEIGHT(mi);
 
454
        tp->width = MI_WIDTH(mi);
 
455
        tp->height = MI_HEIGHT(mi);
433
456
        if (MI_NPIXELS(mi) > 2) {
434
457
                tp->thick_color = NRAND(MI_NPIXELS(mi));
435
458
                /* Insure good contrast */
451
474
        tp->origin.x = (tp->width / 2 + NRAND(tp->width)) / 2;
452
475
        tp->origin.y = (tp->height / 2 + NRAND(tp->height)) / 2;
453
476
        tp->fringe.n_nodes = 2;
454
 
        if (tp->fringe.nodes != 0)
455
 
                release_screen(tp);
456
 
        if (tp->fringe.nodes != 0 || tp->forced.first != 0) {
457
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
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)) {
458
481
                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
459
 
                        (void) fprintf(stderr, "tp->fringe.nodes = 0 && tp->forced.first = 0\n");
 
482
                        (void) fprintf(stderr, "tp->fringe.nodes = NULL && tp->forced.first = 0\n");
460
483
                }
461
 
                release_screen(tp);     /* Try again */
 
484
                free_penrose(tp);       /* Try again */
462
485
                tp->done = True;
463
486
        }
464
487
        tp->forced.n_nodes = tp->forced.n_visible = 0;
465
 
        fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c);
 
488
        if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) {
 
489
                free_penrose(tp);
 
490
                return;
 
491
        }
466
492
        if (fp == 0) {
467
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
493
                if (MI_IS_VERBOSE(mi)) {
468
494
                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
469
495
                        (void) fprintf(stderr, "fp = 0\n");
470
496
                }
471
 
                fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c);
 
497
                if ((fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c)) == NULL) {
 
498
                        free_penrose(tp);
 
499
                        return;
 
500
                }
472
501
                tp->done = True;
473
502
        }
474
503
        /* First vertex. */
475
504
        fp->rule_mask = (1 << N_VERTEX_RULES) - 1;
476
505
        fp->list_ptr = 0;
477
 
        fp->prev = fp->next = ALLOC_NODE(fringe_node_c);
 
506
        if  ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) {
 
507
                free_penrose(tp);
 
508
                return;
 
509
        }
478
510
        if (fp->next == 0) {
479
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
511
                if (MI_IS_VERBOSE(mi)) {
480
512
                        (void) fprintf(stderr, "Weirdness in init_penrose()\n");
481
513
                        (void) fprintf(stderr, "fp->next = 0\n");
482
514
                }
483
 
                fp->prev = fp->next = ALLOC_NODE(fringe_node_c);
 
515
                if ((fp->prev = fp->next = ALLOC_NODE(fringe_node_c)) == NULL) {
 
516
                        free_penrose(tp);
 
517
                        return;
 
518
                }
484
519
                tp->done = True;
485
520
        }
486
521
        fp->n_tiles = 0;
495
530
        fp = fp->next;
496
531
        i = NRAND(5);
497
532
        fp->fived[i] = 2 * NRAND(2) - 1;
498
 
        fp->loc = fived_to_loc(fp->fived, tp);
 
533
        fived_to_loc(fp->fived, tp, &(fp->loc));
499
534
        /* That's it!  We have created our first edge. */
500
535
}
501
536
 
646
681
                else
647
682
                        XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
648
683
        } else
649
 
                XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
 
684
                XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
650
685
        XFillPolygon(display, window, gc, pts, 4, Convex, CoordModeOrigin);
651
 
        XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
 
686
        XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
652
687
        XDrawLines(display, window, gc, pts, 5, CoordModeOrigin);
653
688
 
654
 
        if (ammann) {
 
689
        if (tp->ammann) {
655
690
                /* Draw some Ammann lines for debugging purposes.  This will probably
656
691
                   fail miserably on a b&w display. */
657
692
 
666
701
                        if (MI_NPIXELS(mi) > 2)
667
702
                                XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
668
703
                        else {
669
 
                                XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
 
704
                                XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
670
705
                                XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
671
706
                        }
672
707
                        XDrawLine(display, window, gc,
680
715
                        if (MI_NPIXELS(mi) > 2)
681
716
                                XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color));
682
717
                        else {
683
 
                                XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
 
718
                                XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
684
719
                                XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
685
720
                        }
686
721
                        XDrawLine(display, window, gc,
707
742
 * might get called with an untileable vertex, causing ( n <= 1).
708
743
 * (This is what the tp->done checks for).
709
744
 *
710
 
 * A MI_PAUSE celebrates the dislocation.
 
745
 * A delayLoop celebrates the dislocation.
711
746
 */
712
747
static void
713
748
check_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp)
718
753
 
719
754
        if (vertex->rule_mask == 0) {
720
755
                tp->done = True;
721
 
                if (MI_WIN_IS_VERBOSE(mi)) {
722
 
                        (void) fprintf(stderr, "Dislocation occured!\n");
 
756
                if (MI_IS_VERBOSE(mi)) {
 
757
                        (void) fprintf(stderr, "Dislocation occurred!\n");
723
758
                }
724
 
                MI_PAUSE(mi) = redo_delay_usec; /* Should be able to recover */
 
759
                tp->busyLoop = CELEBRATE;       /* Should be able to recover */
725
760
        }
726
761
        if (1 == find_completions(vertex, hits, n_hits, S_LEFT, 0 /*, False */ ))
727
762
                forced_sides |= S_LEFT;
734
769
                        *vertex->list_ptr = node->next;
735
770
                        if (node->next != 0)
736
771
                                node->next->vertex->list_ptr = vertex->list_ptr;
737
 
                        free(node);
 
772
                        (void) free((void *) node);
738
773
                        tp->forced.n_nodes--;
739
774
                        if (!vertex->off_screen)
740
775
                                tp->forced.n_visible--;
744
779
                forced_node_c *node;
745
780
 
746
781
                if (vertex->list_ptr == 0) {
747
 
                        node = ALLOC_NODE(forced_node_c);
 
782
                        if ((node = ALLOC_NODE(forced_node_c)) == NULL)
 
783
                                return;
748
784
                        node->vertex = vertex;
749
785
                        node->next = tp->forced.first;
750
786
                        if (tp->forced.first != 0)
772
808
{
773
809
        if (tp->fringe.nodes == vertex) {
774
810
                tp->done = True;
775
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
811
                if (MI_IS_VERBOSE(mi)) {
776
812
                        (void) fprintf(stderr, "Weirdness in delete_penrose()\n");
777
813
                        (void) fprintf(stderr, "tp->fringe.nodes == vertex\n");
778
814
                }
779
 
                MI_PAUSE(mi) = redo_delay_usec;
 
815
                tp->busyLoop = CELEBRATE;
780
816
        }
781
817
        if (vertex->list_ptr != 0) {
782
818
                forced_node_c *node = *vertex->list_ptr;
784
820
                *vertex->list_ptr = node->next;
785
821
                if (node->next != 0)
786
822
                        node->next->vertex->list_ptr = vertex->list_ptr;
787
 
                free(node);
 
823
                (void) free((void *) node);
788
824
                tp->forced.n_nodes--;
789
825
                if (!vertex->off_screen)
790
826
                        tp->forced.n_visible--;
791
827
        }
792
828
        if (!vertex->off_screen)
793
829
                tp->fringe.n_nodes--;
794
 
        free(vertex);
 
830
        (void) free((void *) vertex);
795
831
}
796
832
 
797
833
 
798
 
/* Check whether the addition of a tile of type vtype would completely fill *
799
 
   the space available at vertex. */
 
834
/*-
 
835
 * Check whether the addition of a tile of type vtype would completely fill
 
836
 * the space available at vertex.
 
837
 */
800
838
static int
801
839
fills_vertex(ModeInfo * mi, vertex_type_c vtype, fringe_node_c * vertex)
802
840
{
834
872
               fringe_node_c ** right, fringe_node_c ** far,
835
873
               fringe_node_c ** left)
836
874
{
837
 
        fringe_node_c *v, *f = NULL;
 
875
        fringe_node_c *v, *f = (fringe_node_c *) NULL;
838
876
        unsigned    result = FC_NEW_FAR;        /* We clear this later if necessary. */
839
877
 
840
878
        if (far)
908
946
static fringe_node_c *
909
947
alloc_vertex(ModeInfo * mi, angle_c dir, fringe_node_c * from, tiling_c * tp)
910
948
{
911
 
        fringe_node_c *v = ALLOC_NODE(fringe_node_c);
 
949
        fringe_node_c *v;
912
950
 
913
 
        if (v == 0) {
 
951
        if ((v = ALLOC_NODE(fringe_node_c)) == NULL) {
914
952
                tp->done = True;
915
 
                if (MI_WIN_IS_VERBOSE(mi)) {
916
 
                        (void) fprintf(stderr, "Weirdness in alloc_vertex()\n");
917
 
                        (void) fprintf(stderr, "v = 0\n");
 
953
                if (MI_IS_VERBOSE(mi)) {
 
954
                        (void) fprintf(stderr, "No memory in alloc_vertex()\n");
918
955
                }
919
 
                MI_PAUSE(mi) = redo_delay_usec;
 
956
                tp->busyLoop = CELEBRATE;
 
957
                return v;
920
958
        }
921
959
        *v = *from;
922
960
        add_unit_vec(dir, v->fived);
923
 
        v->loc = fived_to_loc(v->fived, tp);
 
961
        fived_to_loc(v->fived, tp, &(v->loc));
924
962
        if (v->loc.x < 0 || v->loc.y < 0
925
963
            || v->loc.x >= tp->width || v->loc.y >= tp->height) {
926
964
                v->off_screen = True;
937
975
        return v;
938
976
}
939
977
 
940
 
/* 
 
978
/*-
941
979
 * Add a tile described by vtype to the side of vertex.  This must be
942
980
 * allowed by the rules -- we do not check it here.  New vertices are
943
981
 * allocated as necessary.  The fringe and the forced vertex pool are updated.
954
992
        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
955
993
 
956
994
        fringe_node_c
957
 
                * left = 0,
958
 
                *right = 0,
959
 
                *far = 0,
 
995
                *left = (fringe_node_c *) NULL,
 
996
                *right = (fringe_node_c *) NULL,
 
997
                *far = (fringe_node_c *) NULL,
960
998
                *node;
961
999
        unsigned    fc = fringe_changes(mi, vertex, side, vtype, &right, &far, &left);
962
1000
 
971
1009
        /* This should never occur. */
972
1010
        if (fc & FC_BAG) {
973
1011
                tp->done = True;
974
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
1012
                if (MI_IS_VERBOSE(mi)) {
975
1013
                        (void) fprintf(stderr, "Weirdness in add_tile()\n");
976
1014
                        (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
977
1015
                }
978
1016
        }
979
1017
        if (side == S_LEFT) {
980
 
                if (right == 0)
981
 
                        right = alloc_vertex(mi,
982
 
                                             vertex_dir(mi, vertex, S_LEFT) - vtype_angle(vtype), vertex, tp);
983
 
                if (far == 0)
984
 
                        far = alloc_vertex(mi,
985
 
                                           vertex_dir(mi, left, S_RIGHT) + vtype_angle(ltype), left, tp);
 
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;
986
1026
        } else {
987
 
                if (left == 0)
988
 
                        left = alloc_vertex(mi,
989
 
                                            vertex_dir(mi, vertex, S_RIGHT) + vtype_angle(vtype), vertex, tp);
990
 
                if (far == 0)
991
 
                        far = alloc_vertex(mi,
992
 
                                           vertex_dir(mi, right, S_LEFT) - vtype_angle(rtype), right, tp);
 
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;
993
1035
        }
994
1036
 
995
1037
        /* Having allocated the new vertices, but before joining them with
1092
1134
        n = find_completions(node->vertex, hits, n, side, &vtype /*, True */ );
1093
1135
        if (n <= 0) {
1094
1136
                tp->done = True;
1095
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
1137
                if (MI_IS_VERBOSE(mi)) {
1096
1138
                        (void) fprintf(stderr, "Weirdness in add_forced_tile()\n");
1097
1139
                        (void) fprintf(stderr, "n = %d\n", n);
1098
1140
                }
1145
1187
                tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color +
1146
1188
                                  MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
1147
1189
        } else
1148
 
                tp->thick_color = tp->thin_color = MI_WIN_WHITE_PIXEL(mi);
 
1190
                tp->thick_color = tp->thin_color = MI_WHITE_PIXEL(mi);
1149
1191
        n_hits = match_rules(vertex, hits, False);
1150
1192
        side = NRAND(2) ? S_LEFT : S_RIGHT;
1151
1193
        n = find_completions(vertex, hits, n_hits, side, vtypes /*, False */ );
1152
1194
        /* One answer would mean a forced tile. */
1153
1195
        if (n <= 0) {
1154
1196
                tp->done = True;
1155
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
1197
                if (MI_IS_VERBOSE(mi)) {
1156
1198
                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1157
1199
                        (void) fprintf(stderr, "n = %d\n", n);
1158
1200
                }
1163
1205
                fc = fringe_changes(mi, vertex, side, vtypes[i], &right, &far, &left);
1164
1206
                if (fc & FC_BAG) {
1165
1207
                        tp->done = True;
1166
 
                        if (MI_WIN_IS_VERBOSE(mi)) {
 
1208
                        if (MI_IS_VERBOSE(mi)) {
1167
1209
                                (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1168
1210
                                (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
1169
1211
                        }
1194
1236
        }
1195
1237
        if (n_good <= 0) {
1196
1238
                tp->done = True;
1197
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
1239
                if (MI_IS_VERBOSE(mi)) {
1198
1240
                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1199
1241
                        (void) fprintf(stderr, "n_good = %d\n", n_good);
1200
1242
                }
1204
1246
                while (no_good & (1 << j))
1205
1247
                        j++;
1206
1248
 
1207
 
        i = add_tile(mi, vertex, side, vtypes[j - 1]);
1208
 
        if (!i) {
 
1249
        if (!add_tile(mi, vertex, side, vtypes[j - 1])) {
1209
1250
                tp->done = True;
1210
 
                if (MI_WIN_IS_VERBOSE(mi)) {
 
1251
                if (MI_IS_VERBOSE(mi)) {
1211
1252
                        (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1212
 
                        (void) fprintf(stderr, "i = %d\n", i);
1213
1253
                }
 
1254
                free_penrose(tp);
1214
1255
        }
1215
1256
}
1216
1257
 
1218
1259
void
1219
1260
draw_penrose(ModeInfo * mi)
1220
1261
{
1221
 
        tiling_c   *tp = &tilings[MI_SCREEN(mi)];
1222
1262
        int         i = 0, n;
1223
 
        forced_node_c *p = tp->forced.first;
1224
 
 
 
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
        }
1225
1278
        if (tp->done || tp->failures >= 100) {
1226
1279
                init_penrose(mi);
1227
1280
                return;
1228
1281
        }
1229
1282
        /* Check for the initial "2-gon". */
1230
1283
        if (tp->fringe.nodes->prev == tp->fringe.nodes->next) {
1231
 
                vertex_type_c vtype = VT_TOTAL_MASK & LRAND();
1232
 
 
1233
 
                XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
1234
 
                (void) add_tile(mi, tp->fringe.nodes, S_LEFT, vtype);
 
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);
1235
1290
                return;
1236
1291
        }
1237
1292
        /* No visible nodes left. */
1238
1293
        if (tp->fringe.n_nodes == 0) {
1239
1294
                tp->done = True;
1240
 
                MI_PAUSE(mi) = redo_delay_usec; /* Just finished drawing */
 
1295
                tp->busyLoop = COMPLETION;      /* Just finished drawing */
1241
1296
                return;
1242
1297
        }
1243
1298
        if (tp->forced.n_visible > 0 && tp->failures < 10) {
1255
1310
                while (i++ < n)
1256
1311
                        p = p->next;
1257
1312
        } else {
1258
 
                fringe_node_c *p = tp->fringe.nodes;
 
1313
                fringe_node_c *fringe_p = tp->fringe.nodes;
1259
1314
 
1260
1315
                n = NRAND(tp->fringe.n_nodes);
1261
1316
                i = 0;
1262
1317
                for (; i <= n; i++)
1263
1318
                        do {
1264
 
                                p = p->next;
1265
 
                        } while (p->off_screen);
1266
 
                add_random_tile(p, mi);
 
1319
                                fringe_p = fringe_p->next;
 
1320
                        } while (fringe_p->off_screen);
 
1321
                add_random_tile(fringe_p, mi);
1267
1322
                tp->failures = 0;
1268
1323
                return;
1269
1324
        }
1281
1336
        if (tilings != NULL) {
1282
1337
                int         screen;
1283
1338
 
1284
 
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1285
 
                        tiling_c   *tp = &tilings[screen];
1286
 
 
1287
 
                        release_screen(tp);
1288
 
                }
 
1339
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
 
1340
                        free_penrose(&tilings[screen]);
1289
1341
                (void) free((void *) tilings);
1290
 
                tilings = NULL;
 
1342
                tilings = (tiling_c *) NULL;
1291
1343
        }
1292
1344
}
 
1345
 
 
1346
#endif /* MODE_penrose */