/* -*- Mode: C; tab-width: 4 -*- */ /* loop --- Chris Langton's self-producing loops */ #if 0 static const char sccsid[] = "@(#)loop.c 5.01 2000/03/15 xlockmore"; #endif /*- * Copyright (c) 1996 by David Bagley. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 15-Mar-2001: Added some flaws, random blue wall spots, to liven it up. * This mod seems to expose a bug where hexagons are erased * for no apparent reason. * 01-Nov-2000: Allocation checks * 16-Jun-2000: Fully coded the hexagonal rules. (Rules that end up in * state zero were not bothered with since a calloc was used * to set non-explicit rules to zero. This allows the * compile-time option RAND_RULES to work here (at least to * generation 540).) * Also added compile-time option DELAYDEBUGLOOP for debugging * life form. This also turns off the random initial direction * of the loop. Set DELAYDEBUGLOOP to be 10 and use with * something like this: * xlock -mode loop -neighbors 6 -size 5 -delay 1 -count 540 -nolock * 18-Oct-1998: Started creating a hexagon version. * It proved not that difficult because I used Langton's Loop * as a guide, hexagons have more neighbors so there is more * freedom to program, and the loop will has six sides to * store its genes (data). * (Soon after this a triangular version with neighbors = 6 * was attempted but was unsuccessful). * 10-May-1997: Compatible with xscreensaver * 15-Nov-1995: Coded from Chris Langton's Self-Reproduction in Cellular * Automata Physica 10D 135-144 1984, also used wire.c as a * guide. */ /*- Grid Number of Neighbors ---- ------------------ Square 4 Hexagon 6 (currently in development) */ /*- * From Steven Levy's Artificial Life * Chris Langton's cellular automata "loops" reproduce in the spirit of life. * Beginning from a single organism, the loops from a colony. As the loops * on the outer fringes reproduce, the inner loops -- blocked by their * daughters -- can no longer produce offspring. These dead progenitors * provide a base for future generations' expansion, much like the formation * of a coral reef. This self-organizing behavior emerges spontaneously, * from the bottom up -- a key characteristic of artificial life. */ /*- Don't Panic -- When the artificial life tries to leave its petri dish (ie. the screen) it will (usually) die... The loops are short of "real" life because a general purpose Turing machine is not contained in the loop. This is a simplification of von Neumann and Codd's self-producing Turing machine. The data spinning around could be viewed as both its DNA and its internal clock. The program can be initalized to have the loop spin both ways... but only one way around will work for a given rule. An open question (at least to me): Is handedness a requirement for (artificial) life? Here there is handedness at both the initial condition and the transition rule. */ #ifndef HAVE_JWXYZ # define DO_STIPPLE #endif #ifdef STANDALONE # define MODE_loop # define DEFAULTS "*delay: 100000 \n" \ "*count: -5 \n" \ "*cycles: 1600 \n" \ "*size: -12 \n" \ "*ncolors: 15 \n" \ "*fpsSolid: true \n" \ "*ignoreRotation: True \n" \ ".lowrez: True \n" \ # define reshape_loop 0 # define loop_handle_event 0 # define UNIFORM_COLORS # include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ # include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ #include "automata.h" #ifdef MODE_loop /*- * neighbors of 0 randomizes between 4 and 6. */ #define DEF_NEIGHBORS "0" /* choose random value */ static int neighbors; static XrmOptionDescRec opts[] = { {"-neighbors", ".loop.neighbors", XrmoptionSepArg, 0} }; static argtype vars[] = { {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int} }; static OptionStruct desc[] = { {"-neighbors num", "squares 4 or hexagons 6"} }; ENTRYPOINT ModeSpecOpt loop_opts = {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; #ifdef USE_MODULES ModStruct loop_description = {"loop", "init_loop", "draw_loop", "release_loop", "refresh_loop", "init_loop", "free_loop", &loop_opts, 100000, 5, 1600, -12, 64, 1.0, "", "Shows Langton's self-producing loops", 0, NULL}; #endif #define LOOPBITS(n,w,h)\ if ((lp->pixmaps[lp->init_bits]=\ XCreatePixmapFromBitmapData(MI_DISPLAY(mi),window,(char *)n,w,h,1,0,1))==None){\ free_loop(mi); return;} else {lp->init_bits++;} static int local_neighbors = 0; #if 0 /* Used to fast forward to troubled generations, mainly used for debugging. -delay 1 -count 170 -neighbors 6 # divisions starts 540 first cell collision 1111 mutant being born from 2 parents 1156 mutant born */ #define DELAYDEBUGLOOP 10 #endif #define COLORS 8 #define REALCOLORS (COLORS-2) #define MINLOOPS 1 #define REDRAWSTEP 2000 /* How many cells to draw per cycle */ #define ADAM_SIZE 8 /* MIN 5 */ #if 1 #define ADAM_LOOPX (ADAM_SIZE+2) #define ADAM_LOOPY (ADAM_SIZE+2) #else #define ADAM_LOOPX 16 #define ADAM_LOOPY 10 #endif #define MINGRIDSIZE (3*ADAM_LOOPX) #if 0 /* TRIA stuff was an attempt to make a triangular lifeform on a hexagonal grid but I got bored. You may need an additional 7th state for a coherent step by step process of cell separation and initial stem development. */ #define TRIA 1 #endif #ifdef TRIA #define HEX_ADAM_SIZE 3 /* MIN 3 */ #else #define HEX_ADAM_SIZE 5 /* MIN 3 */ #endif #if 1 #define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1) #define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1) #else #define HEX_ADAM_LOOPX 3 #define HEX_ADAM_LOOPY 7 #endif #define HEX_MINGRIDSIZE (6*HEX_ADAM_LOOPX) /* #define MINSIZE ((MI_NPIXELS(mi)>=COLORS)?1:(2+(local_neighbors==6))) */ #define MINSIZE 5 #define NEIGHBORKINDS 2 #define ANGLES 360 #define MAXNEIGHBORS 6 /* Singly linked list */ typedef struct _CellList { XPoint pt; struct _CellList *next; } CellList; typedef struct { int init_bits; int generation; int xs, ys; int xb, yb; int nrows, ncols; int bx, by, bnrows, bncols; int mincol, minrow, maxcol, maxrow; int width, height; int redrawing, redrawpos; Bool dead, clockwise; unsigned char *newcells, *oldcells; int ncells[COLORS]; CellList *cellList[COLORS]; unsigned long colors[COLORS]; GC stippledGC; Pixmap pixmaps[COLORS]; union { XPoint hexagon[6]; } shape; } loopstruct; static loopstruct *loops = (loopstruct *) NULL; #define TRANSITION(TT,V) V=TT&7;TT>>=3 #define FINALTRANSITION(TT,V) V=TT&7 #define TABLE(R,T,L,B) (table[((B)<<9)|((L)<<6)|((T)<<3)|(R)]) #define HEX_TABLE(R,T,t,l,b,B) (table[((B)<<15)|((b)<<12)|((l)<<9)|((t)<<6)|((T)<<3)|(R)]) #if 0 /* Instead of setting "unused" state rules to zero it randomizes them. These rules take over when something unexpected happens... like when a cell hits a wall (the end of the screen). */ #define RAND_RULES #endif #ifdef RAND_RULES #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)&=~(7<<((C)*3)));\ (TABLE(R,T,L,B)|=((I)<<((C)*3))) #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)&=~(7<<((C)*3)));\ (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3))) #else #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)|=((I)<<((C)*3))) #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3))) #endif #define TABLE_OUT(C,R,T,L,B) ((TABLE(R,T,L,B)>>((C)*3))&7) #define HEX_TABLE_OUT(C,R,T,t,l,b,B) ((HEX_TABLE(R,T,t,l,b,B)>>((C)*3))&7) static unsigned int *table = (unsigned int *) NULL; /* square: 8*8*8*8 = 2^12 = 2^3^4 = 4096 */ /* hexagon: 8*8*8*8*8*8 = 2^18 = 2^3^6 = 262144 = too big? */ static char plots[NEIGHBORKINDS] = { 4, 6 /* Neighborhoods */ }; static unsigned int transition_table[] = { /* Octal CBLTR->I */ /* CBLTRI CBLTRI CBLTRI CBLTRI CBLTRI */ 0000000, 0025271, 0113221, 0202422, 0301021, 0000012, 0100011, 0122244, 0202452, 0301220, 0000020, 0100061, 0122277, 0202520, 0302511, 0000030, 0100077, 0122434, 0202552, 0401120, 0000050, 0100111, 0122547, 0202622, 0401220, 0000063, 0100121, 0123244, 0202722, 0401250, 0000071, 0100211, 0123277, 0203122, 0402120, 0000112, 0100244, 0124255, 0203216, 0402221, 0000122, 0100277, 0124267, 0203226, 0402326, 0000132, 0100511, 0125275, 0203422, 0402520, 0000212, 0101011, 0200012, 0204222, 0403221, 0000220, 0101111, 0200022, 0205122, 0500022, 0000230, 0101244, 0200042, 0205212, 0500215, 0000262, 0101277, 0200071, 0205222, 0500225, 0000272, 0102026, 0200122, 0205521, 0500232, 0000320, 0102121, 0200152, 0205725, 0500272, 0000525, 0102211, 0200212, 0206222, 0500520, 0000622, 0102244, 0200222, 0206722, 0502022, 0000722, 0102263, 0200232, 0207122, 0502122, 0001022, 0102277, 0200242, 0207222, 0502152, 0001120, 0102327, 0200250, 0207422, 0502220, 0002020, 0102424, 0200262, 0207722, 0502244, 0002030, 0102626, 0200272, 0211222, 0502722, 0002050, 0102644, 0200326, 0211261, 0512122, 0002125, 0102677, 0200423, 0212222, 0512220, 0002220, 0102710, 0200517, 0212242, 0512422, 0002322, 0102727, 0200522, 0212262, 0512722, 0005222, 0105427, 0200575, 0212272, 0600011, 0012321, 0111121, 0200722, 0214222, 0600021, 0012421, 0111221, 0201022, 0215222, 0602120, 0012525, 0111244, 0201122, 0216222, 0612125, 0012621, 0111251, 0201222, 0217222, 0612131, 0012721, 0111261, 0201422, 0222272, 0612225, 0012751, 0111277, 0201722, 0222442, 0700077, 0014221, 0111522, 0202022, 0222462, 0701120, 0014321, 0112121, 0202032, 0222762, 0701220, 0014421, 0112221, 0202052, 0222772, 0701250, 0014721, 0112244, 0202073, 0300013, 0702120, 0016251, 0112251, 0202122, 0300022, 0702221, 0017221, 0112277, 0202152, 0300041, 0702251, 0017255, 0112321, 0202212, 0300076, 0702321, 0017521, 0112424, 0202222, 0300123, 0702525, 0017621, 0112621, 0202272, 0300421, 0702720, 0017721, 0112727, 0202321, 0300622 }; static unsigned int hex_transition_table[] = { /* Octal CBbltTR->I */ /* CBbltTRI CBbltTRI CBbltTRI CBbltTRI CBbltTRI */ #ifdef TRIA 000000000, 000000020, 000000220, 000002220, 000022220, 011122121, 011121221, 011122221, 011221221, 011222221, 011112121, 011112221, 020021122, 020002122, 020211222, 021111222, 020221122, 020027122, 020020722, 020021022, 001127221, 011122727, 011227227, 010122121, 010222211, 021117222, 020112272, 070221220, 001227221, 010221121, 011721221, 011222277, 020111222, 020221172, 070211220, 001217221, 010212277, 010221221, 020122112, 070122220, 001722221, 010221271, 020002022, 021122172, 070121220, 011122277, 011172121, 010212177, 011212277, 070112220, 001772221, 021221772, 070121270, 070721220, 000112721, 000272211, 010022211, 012222277, 020072272, 020227122, 020217222, 010211121, 020002727, 070222220, 001727721, 020021072, 020070722, 070002072, 070007022, 001772721, 070002022, 000000070, 000000770, 000072220, 000000270, 020110222, 020220272, 020220722, 070007071, 070002072, 070007022, 000000012, 000000122, 000000212, 001277721, 020122072, 020202212, 010002121, 020001122, 020002112, 020021722, 020122022, 020027022, 020070122, 020020122, 010227027, 020101222, 010227227, 010227277, 021722172, 001727221, 010222277, 020702272, 070122020, 000172721, 010022277, 010202177, 010227127, 001214221, 010202244, 020024122, 020020422, 040122220, 001422221, 010221241, 010224224, 021122142, 040121220, 001124221, 010224274, 020112242, 021422172, 040221220, 001224221, 001427221, 010222244, 020227042, 040122020, 000142721, 010022244, 010202144, 010224124, 040112220, 001442221, 021221442, 040121240, 040421220, 000242211, 000112421, 020042242, 020214222, 020021422, 020220242, 020024022, 011224224, 020224122, 020220422, 012222244, 020002424, 040222220, 001244421, 000000420, 000000440, 000000240, 000000040, 020040121, 020021042, 040004022, 040004042, 040002042, 010021121, 020011122, 020002112, 001424421, 020040422, 001442421, 040002022, 001724221, 010227247, 020224072, 021417222, 000172421, 010021721, 020017022, 020120212, 020271727, 070207072, 070701220, 000001222, 020110122, 001277221, 001777721, 020021222, 020202272, 020120222, 020221722, 020027227, 070070222, 000007220, 020101272, 020272172, 020721422, 020721722, 020011222, 020202242, #if 0 {2,2,0,0,2,7,0}, {2,0,2,0,2,0,2}, {2,4,1,2,2,1,2}, {2,1,2,1,2,1,2}, {2,0,2,2,1,1,2}, {2,7,1,1,1,1,2}, {0,2,2,2,2,2,2}, {2,2,0,0,7,7,0}, {2,1,2,0,2,0,7}, {2,0,1,2,2,1,2}, {2,4,2,1,2,1,2}, {2,1,2,2,1,1,2}, {2,0,7,1,1,1,2}, {0,2,2,2,2,2,2}, #endif #else 000000000, 000000020, 000000220, 000002220, 011212121, 011212221, 011221221, 011222221, 020002122, 020021122, 020211122, 010221221, 010222121, 020002022, 020021022, 020020122, 020112022, 010202121, 020102022, 020202112, 000000012, 000000122, 000000212, 010002121, 020001122, 020002112, 020011122, 001227221, 001272221, 001272721, 012212277, 011222727, 011212727, 020021722, 020027122, 020020722, 020027022, 020211722, 020202172, 020120272, 020271122, 020202172, 020207122, 020217122, 020120272, 020210722, 020270722, 070212220, 070221220, 070212120, 012222277, 020002727, 070222220, 001277721, 000000070, 000000270, 000000720, 000000770, 020070122, 020021072, 070002072, 070007022, 070007071, 020070722, 070002022, 010227227, 010222727, 010202727, 020172022, 020202712, 001224221, 001242221, 001242421, 012212244, 011222424, 011212424, 020021422, 020024122, 020020422, 020024022, 020211422, 020202142, 020120242, 020241122, 020202142, 020204122, 020214122, 020120242, 020210422, 020240422, 040212220, 040221220, 040212120, 012222244, 020002424, 040222220, 001244421, 000000040, 000000240, 000000420, 000000440, 020040122, 020021042, 040002042, 040004021, 040004042, 020040422, 040002022, 010224224, 010222424, 010202424, 020142022, 020202412, 020011722, 020112072, 020172072, 020142072, 000210225, 000022015, 000022522, 011225521, 020120525, 020020152, 020005122, 020214255, 020021152, 020255242, 050215222, 050225121, 000225220, 001254222, 010221250, 011221251, 011225221, 020025122, 020152152, 020211252, 020214522, 020511125, 050212241, 05221120, 040521225, 000000250, 000000520, 000150220, 000220520, 000222210, 001224251, 010022152, 010251221, 010522121, 011212151, 011221251, 011215221, 020000220, 020002152, 020020220, 020022152, 020021422, 020022152, 020022522, 020025425, 020050422, 020051022, 020051122, 020211122, 020211222, 020215222, 020245122, 050021125, 050021025, 050011125, 051242221, 041225220, 000220250, 000220520, 001227521, 001275221, 011257227, 011522727, 020002052, 020002752, 020021052, 020057125, 050020722, 050027125, 070215220, 070212255, 071225220, 020275122, 051272521, 020055725, 020021552, 012252277, 050002521, 020005725, 050011022, 000000155, 020050722, 001227250, 010512727, 010002151, 020027112, 001227251, 012227257, 050002125, 020517122, 050002025, 020050102, 050002725, 020570722, 001252721, 020007051, 020102052, 020271072, 050001122, 010002151, 011227257, 020051722, 020057022, 020050122, 020051422, 011224254, 012224254, 020054022, 050002425, 040252220, 020002454, 000000540, 001254425, 050004024, 040004051, 000000142, 040001522, 010002547, 020045122, 051221240, 020002512, 020021522, 020020022, 021125522, 020521122, 020025022, 020025522, 020020522, 020202222, 020212222, 021212222, 021222722, 021222422, 020002222, 020021222, 020022122, 020212122, 020027222, 020024222, 020212722, 020212422, 020202122, 001222221, 020002522, 020017125, 010022722, 020212052, 020205052, 070221250, 000000050, 000005220, 000002270, 070252220, 000000450, 000007220, 000220220, 000202220, 000022020, 000020220, 000222040, 000220440, 000022040, 000040220, 000252220, 050221120, 010221520, 002222220, 000070220, 000220720, 000020520, 000070250, 000222070, 000027020, 000022070, 000202270, 000024020, 000220420, 000220270, 000220240, 000072020, 000042020, 000002020, 000002070, 000020270, 000020250, 000270270, 000007020, 000040270, /* Collision starts (gen 540), not sure to have rules to save it or depend on calloc to intialize remaining rules to 0 so that the mutant will be born */ 000050220, #endif }; /*- Neighborhoods are read as follows (rotations are not listed): T L C R ==> I B t T l C R ==> I b B */ static unsigned char self_reproducing_loop[ADAM_LOOPY][ADAM_LOOPX] = { /* 10x10 */ {0, 2, 2, 2, 2, 2, 2, 2, 2, 0}, {2, 4, 0, 1, 4, 0, 1, 1, 1, 2}, {2, 1, 2, 2, 2, 2, 2, 2, 1, 2}, {2, 0, 2, 0, 0, 0, 0, 2, 1, 2}, {2, 7, 2, 0, 0, 0, 0, 2, 7, 2}, {2, 1, 2, 0, 0, 0, 0, 2, 0, 2}, {2, 0, 2, 0, 0, 0, 0, 2, 1, 2}, {2, 7, 2, 2, 2, 2, 2, 2, 7, 2}, {2, 1, 0, 6, 1, 0, 7, 1, 0, 2}, {0, 2, 2, 2, 2, 2, 2, 2, 2, 0} }; static unsigned char hex_self_reproducing_loop[HEX_ADAM_LOOPY][HEX_ADAM_LOOPX] = { #if 0 /* Experimental TRIA5:7x7 */ {2,2,0,0,0,0,0}, {2,1,2,0,2,2,0}, {2,0,4,2,2,0,2}, {2,7,2,0,2,0,2}, {2,1,2,2,1,1,2}, {2,0,7,1,0,7,2}, {0,2,2,2,2,2,2}, /* Stem cells, only "5" will fully reproduce itself */ /* 3:12x7 */ {2,2,2,2,0,0,0,0,0,0,0,0}, {2,1,1,1,2,0,0,0,0,0,0,0}, {2,1,2,2,1,2,2,2,2,2,2,0}, {2,1,2,0,2,7,1,1,1,1,1,2}, {0,2,1,2,2,0,2,2,2,2,2,2}, {0,0,2,0,4,1,2,0,0,0,0,0}, {0,0,0,2,2,2,2,0,0,0,0,0} /* 4:14x9 */ {2,2,2,2,2,0,0,0,0,0,0,0,0,0}, {2,1,1,1,1,2,0,0,0,0,0,0,0,0}, {2,1,2,2,2,1,2,0,0,0,0,0,0,0}, {2,1,2,0,0,2,1,2,2,2,2,2,2,0}, {2,1,2,0,0,0,2,7,1,1,1,1,1,2}, {0,2,1,2,0,0,2,0,2,2,2,2,2,2}, {0,0,2,0,2,2,2,1,2,0,0,0,0,0}, {0,0,0,2,4,1,0,7,2,0,0,0,0,0}, {0,0,0,0,2,2,2,2,2,0,0,0,0,0} /* 5:16x11 */ {2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0}, {2,1,1,1,1,1,2,0,0,0,0,0,0,0,0,0}, {2,1,2,2,2,2,1,2,0,0,0,0,0,0,0,0}, {2,1,2,0,0,0,2,1,2,0,0,0,0,0,0,0}, {2,1,2,0,0,0,0,2,1,2,2,2,2,2,2,0}, {2,1,2,0,0,0,0,0,2,7,1,1,1,1,1,2}, {0,2,1,2,0,0,0,0,2,0,2,2,2,2,2,2}, {0,0,2,0,2,0,0,0,2,1,2,0,0,0,0,0}, {0,0,0,2,4,2,2,2,2,7,2,0,0,0,0,0}, {0,0,0,0,2,1,0,7,1,0,2,0,0,0,0,0}, {0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0} /* test:3x7 (0,4) is blank ... very strange. init_adam seems ok something after that I guess */ {2,2,0}, {2,0,2}, {0,2,2}, {0,0,0}, {2,2,0}, {2,1,2}, {0,2,2}, #else /* this might be better for hexagons, spacewise efficient... */ #ifdef TRIA /* Experimental TRIA5:7x7 */ {2,2,0,0,2,2,0}, {2,4,2,0,2,7,2}, {2,1,0,2,2,0,2}, {2,0,2,1,2,1,2}, {2,7,2,2,7,7,2}, {2,1,0,7,1,0,2}, {0,2,2,2,2,2,2}, #else /* 5:11x11 */ {2,2,2,2,2,2,0,0,0,0,0}, {2,1,1,7,0,1,2,0,0,0,0}, {2,1,2,2,2,2,7,2,0,0,0}, {2,1,2,0,0,0,2,0,2,0,0}, {2,1,2,0,0,0,0,2,1,2,0}, {2,1,2,0,0,0,0,0,2,7,2}, {0,2,1,2,0,0,0,0,2,0,2}, {0,0,2,1,2,0,0,0,2,1,2}, {0,0,0,2,1,2,2,2,2,4,2}, {0,0,0,0,2,1,1,1,1,5,2}, {0,0,0,0,0,2,2,2,2,2,2} #endif #endif }; static void position_of_neighbor(int dir, int *pcol, int *prow) { int col = *pcol, row = *prow; /* NO WRAPING */ if (local_neighbors == 6) { switch (dir) { case 0: col++; break; case 60: col += (row & 1); row--; break; case 120: col -= !(row & 1); row--; break; case 180: col--; break; case 240: col -= !(row & 1); row++; break; case 300: col += (row & 1); row++; break; default: (void) fprintf(stderr, "wrong direction %d\n", dir); } } else { switch (dir) { case 0: col++; break; case 90: row--; break; case 180: col--; break; case 270: row++; break; default: (void) fprintf(stderr, "wrong direction %d\n", dir); } } *pcol = col; *prow = row; } static Bool withinBounds(loopstruct * lp, int col, int row) { return (row >= 1 && row < lp->bnrows - 1 && col >= 1 && col < lp->bncols - 1 - (local_neighbors == 6 && (row % 2))); } static void fillcell(ModeInfo * mi, GC gc, int col, int row) { loopstruct *lp = &loops[MI_SCREEN(mi)]; if (local_neighbors == 6) { int ccol = 2 * col + !(row & 1), crow = 2 * row; lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; if (lp->xs == 1 && lp->ys == 1) XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); else XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, lp->shape.hexagon, 6, Convex, CoordModePrevious); } else { XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs - (lp->xs > 3), lp->ys - (lp->ys > 3)); } } static void drawcell(ModeInfo * mi, int col, int row, int state) { loopstruct *lp = &loops[MI_SCREEN(mi)]; XGCValues gcv; GC gc; if (MI_NPIXELS(mi) >= COLORS) { gc = MI_GC(mi); XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]); } else { #ifdef DO_STIPPLE gcv.stipple = lp->pixmaps[state]; #endif /* DO_STIPPLE */ gcv.foreground = MI_WHITE_PIXEL(mi); gcv.background = MI_BLACK_PIXEL(mi); XChangeGC(MI_DISPLAY(mi), lp->stippledGC, #ifdef DO_STIPPLE GCStipple | #endif /* DO_STIPPLE */ GCForeground | GCBackground, &gcv); gc = lp->stippledGC; } fillcell(mi, gc, col, row); } #ifdef DEBUG static void print_state(ModeInfo * mi, int state) { loopstruct *lp = &loops[MI_SCREEN(mi)]; CellList *locallist = lp->cellList[state]; int i = 0; (void) printf("state %d\n", state); while (locallist) { (void) printf("%d x %d, y %d\n", i, locallist->pt.x, locallist->pt.y); locallist = locallist->next; i++; } } #endif static void free_state(loopstruct * lp, int state) { CellList *current; while (lp->cellList[state]) { current = lp->cellList[state]; lp->cellList[state] = lp->cellList[state]->next; (void) free((void *) current); } lp->ncells[state] = 0; } static void free_list(loopstruct * lp) { int state; for (state = 0; state < COLORS; state++) free_state(lp, state); } ENTRYPOINT void free_loop(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); loopstruct *lp = &loops[MI_SCREEN(mi)]; int shade; for (shade = 0; shade < lp->init_bits; shade++) if (lp->pixmaps[shade] != None) { XFreePixmap(display, lp->pixmaps[shade]); lp->pixmaps[shade] = None; } if (lp->stippledGC != None) { XFreeGC(display, lp->stippledGC); lp->stippledGC = None; } if (lp->oldcells != NULL) { (void) free((void *) lp->oldcells); lp->oldcells = (unsigned char *) NULL; } if (lp->newcells != NULL) { (void) free((void *) lp->newcells); lp->newcells = (unsigned char *) NULL; } free_list(lp); } static Bool addtolist(ModeInfo * mi, int col, int row, unsigned char state) { loopstruct *lp = &loops[MI_SCREEN(mi)]; CellList *current = lp->cellList[state]; if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) == NULL) { lp->cellList[state] = current; free_loop(mi); return False; } lp->cellList[state]->pt.x = col; lp->cellList[state]->pt.y = row; lp->cellList[state]->next = current; lp->ncells[state]++; return True; } static Bool draw_state(ModeInfo * mi, int state) { loopstruct *lp = &loops[MI_SCREEN(mi)]; Display *display = MI_DISPLAY(mi); GC gc; XGCValues gcv; CellList *current = lp->cellList[state]; if (MI_NPIXELS(mi) >= COLORS) { gc = MI_GC(mi); XSetForeground(display, gc, lp->colors[state]); } else { #ifdef DO_STIPPLE gcv.stipple = lp->pixmaps[state]; #endif /* DO_STIPPLE */ gcv.foreground = MI_WHITE_PIXEL(mi); gcv.background = MI_BLACK_PIXEL(mi); XChangeGC(display, lp->stippledGC, #ifdef DO_STIPPLE GCStipple | #endif /* DO_STIPPLE */ GCForeground | GCBackground, &gcv); gc = lp->stippledGC; } if (local_neighbors == 6) { /* Draw right away, slow */ while (current) { int col, row, ccol, crow; col = current->pt.x; row = current->pt.y; ccol = 2 * col + !(row & 1), crow = 2 * row; lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; if (lp->xs == 1 && lp->ys == 1) XDrawPoint(display, MI_WINDOW(mi), gc, lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); else XFillPolygon(display, MI_WINDOW(mi), gc, lp->shape.hexagon, 6, Convex, CoordModePrevious); current = current->next; } } else { /* Take advantage of XFillRectangles */ XRectangle *rects; int nrects = 0; /* Create Rectangle list from part of the cellList */ if ((rects = (XRectangle *) malloc(lp->ncells[state] * sizeof (XRectangle))) == NULL) { return False; } while (current) { rects[nrects].x = lp->xb + current->pt.x * lp->xs; rects[nrects].y = lp->yb + current->pt.y * lp->ys; rects[nrects].width = lp->xs - (lp->xs > 3); rects[nrects].height = lp->ys - (lp->ys > 3); current = current->next; nrects++; } /* Finally get to draw */ XFillRectangles(display, MI_WINDOW(mi), gc, rects, nrects); /* Free up rects list and the appropriate part of the cellList */ (void) free((void *) rects); } free_state(lp, state); return True; } static Bool init_table(void) { if (table == NULL) { int mult = 1; unsigned int tt, c, n[MAXNEIGHBORS], i; int j, k; int size_transition_table = sizeof (transition_table) / sizeof (unsigned int); int size_hex_transition_table = sizeof (hex_transition_table) / sizeof (unsigned int); for (j = 0; j < local_neighbors; j++) mult *= 8; if ((table = (unsigned int *) calloc(mult, sizeof (unsigned int))) == NULL) { return False; } #ifdef RAND_RULES /* Here I was interested to see what happens when it hits a wall.... Rules not normally used take over... takes too much time though */ /* Each state = 3 bits */ if (MAXRAND < 16777216.0) { for (j = 0; j < mult; j++) { table[j] = (unsigned int) ((NRAND(4096) << 12) & NRAND(4096)); } } else { for (j = 0; j < mult; j++) { table[j] = (unsigned int) (NRAND(16777216)); } } #endif if (local_neighbors == 6) { for (j = 0; j < size_hex_transition_table; j++) { tt = hex_transition_table[j]; TRANSITION(tt, i); for (k = 0; k < local_neighbors; k++) { TRANSITION(tt, n[k]); } FINALTRANSITION(tt, c); HEX_TABLE_IN(c, n[0], n[1], n[2], n[3], n[4], n[5], i); HEX_TABLE_IN(c, n[1], n[2], n[3], n[4], n[5], n[0], i); HEX_TABLE_IN(c, n[2], n[3], n[4], n[5], n[0], n[1], i); HEX_TABLE_IN(c, n[3], n[4], n[5], n[0], n[1], n[2], i); HEX_TABLE_IN(c, n[4], n[5], n[0], n[1], n[2], n[3], i); HEX_TABLE_IN(c, n[5], n[0], n[1], n[2], n[3], n[4], i); } } else { for (j = 0; j < size_transition_table; j++) { tt = transition_table[j]; TRANSITION(tt, i); for (k = 0; k < local_neighbors; k++) { TRANSITION(tt, n[k]); } FINALTRANSITION(tt, c); TABLE_IN(c, n[0], n[1], n[2], n[3], i); TABLE_IN(c, n[1], n[2], n[3], n[0], i); TABLE_IN(c, n[2], n[3], n[0], n[1], i); TABLE_IN(c, n[3], n[0], n[1], n[2], i); } } } return True; } static void init_flaw(ModeInfo * mi) { loopstruct *lp = &loops[MI_SCREEN(mi)]; int a, b; #define BLUE 2 if (lp->bncols <= 3 || lp->bnrows <= 3) return; a = MIN(lp->bncols - 3, 2 * ((local_neighbors == 6) ? HEX_MINGRIDSIZE : MINGRIDSIZE)); a = NRAND(a) + (lp->bncols - a) / 2; b = MIN(lp->bnrows - 3, 2 * ((local_neighbors == 6) ? HEX_MINGRIDSIZE : MINGRIDSIZE)); b = NRAND(b) + (lp->bnrows - b) / 2; if (lp->mincol > a) lp->mincol = a; if (lp->minrow > b) lp->minrow = b; if (lp->maxcol < a + 2) lp->maxcol = a + 2; if (lp->maxrow < b + 2) lp->maxrow = b + 2; if (local_neighbors == 6) { lp->newcells[b * lp->bncols + a + !(b % 2) ] = BLUE; lp->newcells[b * lp->bncols + a + 1 + !(b % 2)] = BLUE; lp->newcells[(b + 1) * lp->bncols + a] = BLUE; lp->newcells[(b + 1) * lp->bncols + a + 2] = BLUE; lp->newcells[(b + 2) * lp->bncols + a + !(b % 2)] = BLUE; lp->newcells[(b + 2) * lp->bncols + a + 1 + !(b % 2)] = BLUE; } else { int orient = NRAND(4); lp->newcells[lp->bncols * (b + 1) + a + 1] = BLUE; if (orient == 0 || orient == 1) { lp->newcells[lp->bncols * b + a + 1] = BLUE; } if (orient == 1 || orient == 2) { lp->newcells[lp->bncols * (b + 1) + a + 2] = BLUE; } if (orient == 2 || orient == 3) { lp->newcells[lp->bncols * (b + 2) + a + 1] = BLUE; } if (orient == 3 || orient == 0) { lp->newcells[lp->bncols * (b + 1) + a] = BLUE; } } } static void init_adam(ModeInfo * mi) { loopstruct *lp = &loops[MI_SCREEN(mi)]; XPoint start = { 0, 0 }, dirx = { 0, 0 }, diry = { 0, 0 }; int i, j, dir; #ifdef DELAYDEBUGLOOP lp->clockwise = 0; if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ #endif lp->clockwise = (Bool) (LRAND() & 1); #ifdef DELAYDEBUGLOOP dir = 0; if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ #endif dir = NRAND(local_neighbors); if (local_neighbors == 6) { int k; switch (dir) { case 0: start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; if (lp->mincol > start.x - 2) lp->mincol = start.x - 2; if (lp->minrow > start.y - 1) lp->minrow = start.y - 1; if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = (lp->clockwise) ? hex_self_reproducing_loop[i][j] : hex_self_reproducing_loop[j][i]; } } break; case 1: start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; if (lp->mincol > start.x - 1) lp->mincol = start.x - 1; if (lp->minrow > start.y - HEX_ADAM_LOOPX) lp->minrow = start.y - HEX_ADAM_LOOPX; if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) ? -(i + j + 1) / 2 : -(i + j) / 2); lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = (lp->clockwise) ? hex_self_reproducing_loop[i][j] : hex_self_reproducing_loop[j][i]; } } break; case 2: start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; if (lp->mincol > start.x - 2) lp->mincol = start.x - 2; if (lp->minrow > start.y - 1) lp->minrow = start.y - 1; if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPX; j++) { for (i = 0; i < HEX_ADAM_LOOPY; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = (lp->clockwise) ? hex_self_reproducing_loop[j][HEX_ADAM_LOOPX - i - 1] : hex_self_reproducing_loop[i][HEX_ADAM_LOOPY - j - 1]; } } break; case 3: start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; if (lp->mincol > start.x - 1) lp->mincol = start.x - 1; if (lp->minrow > start.y - 1) lp->minrow = start.y - 1; if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = (lp->clockwise) ? hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; } } break; case 4: start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; if (lp->mincol > start.x - 1) lp->mincol = start.x - 1; if (lp->minrow > start.y - HEX_ADAM_LOOPX) lp->minrow = start.y - HEX_ADAM_LOOPX; if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) ? -(i + j + 1) / 2 : -(i + j) / 2); lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = (lp->clockwise) ? hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; } } break; case 5: start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; if (lp->mincol > start.x - 2) lp->mincol = start.x - 2; if (lp->minrow > start.y - 1) lp->minrow = start.y - 1; if (lp->maxcol < start.x + HEX_ADAM_LOOPY + 1) lp->maxcol = start.x + HEX_ADAM_LOOPY + 1; if (lp->maxrow < start.y + HEX_ADAM_LOOPX + 1) lp->maxrow = start.y + HEX_ADAM_LOOPX + 1; for (j = 0; j < HEX_ADAM_LOOPX; j++) { for (i = 0; i < HEX_ADAM_LOOPY; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = (lp->clockwise) ? hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][i] : hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j]; } } break; } #if DEBUGTEST /* (void) printf ("s %d s %d \n", start.x, start.y); */ (void) printf ("%d %d %d %d %d\n", start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, start.y + j - lp->by, i, j, hex_self_reproducing_loop[j][i]); /* Draw right away */ drawcell(mi, start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, start.y + j - lp->by, hex_self_reproducing_loop[j][i]); #endif } else { switch (dir) { case 0: start.x = (lp->bncols - ADAM_LOOPX) / 2; start.y = (lp->bnrows - ADAM_LOOPY) / 2; dirx.x = 1, dirx.y = 0; diry.x = 0, diry.y = 1; if (lp->mincol > start.x) lp->mincol = start.x; if (lp->minrow > start.y) lp->minrow = start.y; if (lp->maxcol < start.x + ADAM_LOOPX) lp->maxcol = start.x + ADAM_LOOPX; if (lp->maxrow < start.y + ADAM_LOOPY) lp->maxrow = start.y + ADAM_LOOPY; break; case 1: start.x = (lp->bncols + ADAM_LOOPY) / 2; start.y = (lp->bnrows - ADAM_LOOPX) / 2; dirx.x = 0, dirx.y = 1; diry.x = -1, diry.y = 0; if (lp->mincol > start.x - ADAM_LOOPY) lp->mincol = start.x - ADAM_LOOPY; if (lp->minrow > start.y) lp->minrow = start.y; if (lp->maxcol < start.x) lp->maxcol = start.x; if (lp->maxrow < start.y + ADAM_LOOPX) lp->maxrow = start.y + ADAM_LOOPX; break; case 2: start.x = (lp->bncols + ADAM_LOOPX) / 2; start.y = (lp->bnrows + ADAM_LOOPY) / 2; dirx.x = -1, dirx.y = 0; diry.x = 0, diry.y = -1; if (lp->mincol > start.x - ADAM_LOOPX) lp->mincol = start.x - ADAM_LOOPX; if (lp->minrow > start.y - ADAM_LOOPY) lp->minrow = start.y - ADAM_LOOPY; if (lp->maxcol < start.x) lp->maxcol = start.x; if (lp->maxrow < start.y) lp->maxrow = start.y; break; case 3: start.x = (lp->bncols - ADAM_LOOPY) / 2; start.y = (lp->bnrows + ADAM_LOOPX) / 2; dirx.x = 0, dirx.y = -1; diry.x = 1, diry.y = 0; if (lp->mincol > start.x) lp->mincol = start.x; if (lp->minrow > start.y - ADAM_LOOPX) lp->minrow = start.y - ADAM_LOOPX; if (lp->maxcol < start.x + ADAM_LOOPX) lp->maxcol = start.x + ADAM_LOOPX; if (lp->maxrow < start.y) lp->maxrow = start.y; break; } for (j = 0; j < ADAM_LOOPY; j++) for (i = 0; i < ADAM_LOOPX; i++) lp->newcells[lp->bncols * (start.y + dirx.y * i + diry.y * j) + start.x + dirx.x * i + diry.x * j] = (lp->clockwise) ? self_reproducing_loop[j][ADAM_LOOPX - i - 1] : self_reproducing_loop[j][i]; #if DEBUG /* Draw right away */ drawcell(mi, start.x + dirx.x * i + diry.x * j - lp->bx, start.y + dirx.y * i + diry.y * j - lp->by, (lp->clockwise) ? self_reproducing_loop[j][ADAM_LOOPX - i - i] : self_reproducing_loop[j][i]); #endif } } static void do_gen(loopstruct * lp) { int i, j, k; unsigned char *z; unsigned int n[MAXNEIGHBORS]; unsigned int c; #define LOC(X, Y) (*(lp->oldcells + (X) + ((Y) * lp->bncols))) for (j = lp->minrow; j <= lp->maxrow; j++) { for (i = lp->mincol; i <= lp->maxcol; i++) { z = lp->newcells + i + j * lp->bncols; c = LOC(i, j); for (k = 0; k < local_neighbors; k++) { int newi = i, newj = j; position_of_neighbor(k * ANGLES / local_neighbors, &newi, &newj); n[k] = 0; if (withinBounds(lp, newi, newj)) { n[k] = LOC(newi, newj); } } if (local_neighbors == 6) { *z = (lp->clockwise) ? HEX_TABLE_OUT(c, n[5], n[4], n[3], n[2], n[1], n[0]) : HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]); } else { *z = (lp->clockwise) ? TABLE_OUT(c, n[3], n[2], n[1], n[0]) : TABLE_OUT(c, n[0], n[1], n[2], n[3]); } } } } ENTRYPOINT void release_loop (ModeInfo * mi) { if (table != NULL) { (void) free((void *) table); table = (unsigned int *) NULL; } } static void *stop_warning_about_triangleUnit_already; ENTRYPOINT void init_loop (ModeInfo * mi) { int i, size = MI_SIZE(mi); loopstruct *lp; stop_warning_about_triangleUnit_already = (void *) &triangleUnit; MI_INIT (mi, loops); lp = &loops[MI_SCREEN(mi)]; lp->redrawing = 0; if (MI_WIDTH(mi) < 100 || MI_HEIGHT(mi) < 100) /* tiny window */ size = MIN(MI_WIDTH(mi), MI_HEIGHT(mi)); #ifdef DO_STIPPLE if ((MI_NPIXELS(mi) < COLORS) && (lp->init_bits == 0)) { Window window = MI_WINDOW(mi); XGCValues gcv; if (lp->stippledGC == None) { gcv.fill_style = FillOpaqueStippled; if ((lp->stippledGC = XCreateGC(MI_DISPLAY(mi), window, GCFillStyle, &gcv)) == None) { free_loop(mi); return; } } LOOPBITS(stipples[0], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[2], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[3], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[4], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[6], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[7], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[8], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[10], STIPPLESIZE, STIPPLESIZE); } #endif /* DO_STIPPLE */ if (MI_NPIXELS(mi) >= COLORS) { /* Maybe these colors should be randomized */ lp->colors[0] = MI_BLACK_PIXEL(mi); lp->colors[1] = MI_PIXEL(mi, 0); /* RED */ lp->colors[5] = MI_PIXEL(mi, MI_NPIXELS(mi) / REALCOLORS); /* YELLOW */ lp->colors[4] = MI_PIXEL(mi, 2 * MI_NPIXELS(mi) / REALCOLORS); /* GREEN */ lp->colors[6] = MI_PIXEL(mi, 3 * MI_NPIXELS(mi) / REALCOLORS); /* CYAN */ lp->colors[2] = MI_PIXEL(mi, 4 * MI_NPIXELS(mi) / REALCOLORS); /* BLUE */ lp->colors[3] = MI_PIXEL(mi, 5 * MI_NPIXELS(mi) / REALCOLORS); /* MAGENTA */ lp->colors[7] = MI_WHITE_PIXEL(mi); } free_list(lp); lp->generation = 0; lp->width = MI_WIDTH(mi); lp->height = MI_HEIGHT(mi); if (!local_neighbors) { for (i = 0; i < NEIGHBORKINDS; i++) { if (neighbors == plots[i]) { local_neighbors = neighbors; break; } if (i == NEIGHBORKINDS - 1) { #if 1 local_neighbors = plots[NRAND(NEIGHBORKINDS)]; #else local_neighbors = 4; #endif break; } } } if (local_neighbors == 6) { int nccols, ncrows; if (lp->width < 8) lp->width = 8; if (lp->height < 8) lp->height = 8; if (size < -MINSIZE) { lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; } else if (size < MINSIZE) { if (!size) lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE); else lp->ys = MINSIZE; } else lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE)); lp->xs = lp->ys; nccols = MAX(lp->width / lp->xs - 2, HEX_MINGRIDSIZE); ncrows = MAX(lp->height / lp->ys - 1, HEX_MINGRIDSIZE); lp->ncols = nccols / 2; lp->nrows = ncrows / 2; lp->nrows -= !(lp->nrows & 1); /* Must be odd */ lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs; lp->yb = (lp->height - lp->ys * ncrows) / 2 + lp->ys; for (i = 0; i < 6; i++) { lp->shape.hexagon[i].x = (lp->xs - 1) * hexagonUnit[i].x; lp->shape.hexagon[i].y = ((lp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; } } else { if (size < -MINSIZE) lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; else if (size < MINSIZE) { if (!size) lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE); else lp->ys = MINSIZE; } else lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE)); lp->xs = lp->ys; lp->ncols = MAX(lp->width / lp->xs, ADAM_LOOPX + 1); lp->nrows = MAX(lp->height / lp->ys, ADAM_LOOPX + 1); lp->xb = (lp->width - lp->xs * lp->ncols) / 2; lp->yb = (lp->height - lp->ys * lp->nrows) / 2; } lp->bx = 1; lp->by = 1; lp->bncols = lp->ncols + 2 * lp->bx; lp->bnrows = lp->nrows + 2 * lp->by; MI_CLEARWINDOW(mi); if (lp->oldcells != NULL) { (void) free((void *) lp->oldcells); lp->oldcells = (unsigned char *) NULL; } if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) { free_loop(mi); return; } if (lp->newcells != NULL) { (void) free((void *) lp->newcells); lp->newcells = (unsigned char *) NULL; } if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) { free_loop(mi); return; } if (!init_table()) { release_loop(mi); return; } lp->mincol = lp->bncols - 1; lp->minrow = lp->bnrows - 1; lp->maxcol = 0; lp->maxrow = 0; #ifndef DELAYDEBUGLOOP { int flaws = MI_COUNT(mi); if (flaws < 0) flaws = NRAND(-MI_COUNT(mi) + 1); for (i = 0; i < flaws; i++) { init_flaw(mi); } /* actual flaws might be less since the adam loop done next */ } #endif init_adam(mi); } ENTRYPOINT void draw_loop (ModeInfo * mi) { int offset, i, j; unsigned char *z, *znew; loopstruct *lp; if (loops == NULL) return; lp = &loops[MI_SCREEN(mi)]; if (lp->newcells == NULL) return; MI_IS_DRAWN(mi) = True; lp->dead = True; #ifdef DELAYDEBUGLOOP if (MI_COUNT(mi) && lp->generation > MI_COUNT(mi)) { (void) sleep(DELAYDEBUGLOOP); } #endif for (j = lp->minrow; j <= lp->maxrow; j++) { for (i = lp->mincol; i <= lp->maxcol; i++) { offset = j * lp->bncols + i; z = lp->oldcells + offset; znew = lp->newcells + offset; if (*z != *znew) { lp->dead = False; *z = *znew; if (!addtolist(mi, i - lp->bx, j - lp->by, *znew)) return; if (i == lp->mincol && i > lp->bx) lp->mincol--; if (j == lp->minrow && j > lp->by) lp->minrow--; if (i == lp->maxcol && i < lp->bncols - 2 * lp->bx) lp->maxcol++; if (j == lp->maxrow && j < lp->bnrows - 2 * lp->by) lp->maxrow++; } } } for (i = 0; i < COLORS; i++) if (!draw_state(mi, i)) { free_loop(mi); return; } if (++lp->generation > MI_CYCLES(mi) || lp->dead) { init_loop(mi); return; } else do_gen(lp); if (lp->redrawing) { for (i = 0; i < REDRAWSTEP; i++) { if ((*(lp->oldcells + lp->redrawpos))) { drawcell(mi, lp->redrawpos % lp->bncols - lp->bx, lp->redrawpos / lp->bncols - lp->by, *(lp->oldcells + lp->redrawpos)); } if (++(lp->redrawpos) >= lp->bncols * (lp->bnrows - lp->bx)) { lp->redrawing = 0; break; } } } } #ifndef STANDALONE ENTRYPOINT void refresh_loop (ModeInfo * mi) { loopstruct *lp; if (loops == NULL) return; lp = &loops[MI_SCREEN(mi)]; MI_CLEARWINDOW(mi); lp->redrawing = 1; lp->redrawpos = lp->by * lp->ncols + lp->bx; } #endif XSCREENSAVER_MODULE ("Loop", loop) #endif /* MODE_loop */