3
Miscellaneous fractal-specific code (formerly in CALCFRAC.C)
9
/* see Fractint.c for a description of the "include" hierarchy */
15
/* routines in this module */
17
static void set_Plasma_palette(void);
18
static U16 _fastcall adjust(int xa,int ya,int x,int y,int xb,int yb);
19
static void _fastcall subDivide(int x1,int y1,int x2,int y2);
20
static int _fastcall new_subD (int x1,int y1,int x2,int y2, int recur);
21
static void verhulst(void);
22
static void Bif_Period_Init(void);
23
static int _fastcall Bif_Periodic(long);
24
static void set_Cellular_palette(void);
26
U16 (_fastcall *getpix)(int,int) = (U16(_fastcall *)(int,int))getcolor;
28
typedef void (_fastcall *PLOT)(int,int,int);
30
/***************** standalone engine for "test" ********************/
34
int startrow,startpass,numpasses;
35
startrow = startpass = 0;
39
get_resume(sizeof(startrow),&startrow,sizeof(startpass),&startpass,0);
42
if(teststart()) /* assume it was stand-alone, doesn't want passes logic */
44
numpasses = (stdcalcmode == '1') ? 0 : 1;
45
for (passes=startpass; passes <= numpasses ; passes++)
47
for (row = startrow; row <= iystop; row=row+1+numpasses)
49
for (col = 0; col <= ixstop; col++) /* look at each point on screen */
58
put_resume(sizeof(row),&row,sizeof(passes),&passes,0);
61
color = testpt(init.x,init.y,parm.x,parm.y,maxit,inside);
62
if (color >= colors) { /* avoid trouble if color is 0 */
66
color = ((color-1) % andcolor) + 1; /* skip color zero */
68
(*plot)(col,row,color);
69
if(numpasses && (passes == 0))
70
(*plot)(col,row+1,color);
73
startrow = passes + 1;
79
/***************** standalone engine for "plasma" ********************/
81
static int iparmx; /* iparmx = parm.x * 8 */
82
static int shiftvalue; /* shift based on #colors */
85
static int recur_level = 0;
88
/* returns a random 16 bit value that is never 0 */
92
value = (U16)rand15();
94
value = (U16)(value + (rand15()&1));
100
void _fastcall putpot(int x, int y, U16 color)
104
putcolor(x, y, color >> 8 ? color >> 8 : 1); /* don't write 0 */
105
/* we don't write this if dotmode==11 because the above putcolor
106
was already a "writedisk" in that case */
108
writedisk(x+sxoffs,y+syoffs,color >> 8); /* upper 8 bits */
109
writedisk(x+sxoffs,y+sydots+syoffs,color&255); /* lower 8 bits */
113
void _fastcall putpotborder(int x, int y, U16 color)
115
if((x==0) || (y==0) || (x==xdots-1) || (y==ydots-1))
116
color = (U16)outside;
121
void _fastcall putcolorborder(int x, int y, int color)
123
if((x==0) || (y==0) || (x==xdots-1) || (y==ydots-1))
130
U16 _fastcall getpot(int x, int y)
134
color = (U16)readdisk(x+sxoffs,y+syoffs);
135
color = (U16)((color << 8) + (U16) readdisk(x+sxoffs,y+sydots+syoffs));
139
static int plasma_check; /* to limit kbd checking */
141
static U16 _fastcall adjust(int xa,int ya,int x,int y,int xb,int yb)
144
pseudorandom = ((S32)iparmx)*((rand15()-16383));
145
/* pseudorandom = pseudorandom*(abs(xa-xb)+abs(ya-yb));*/
146
pseudorandom = pseudorandom * recur1;
147
pseudorandom = pseudorandom >> shiftvalue;
148
pseudorandom = (((S32)getpix(xa,ya)+(S32)getpix(xb,yb)+1)>>1)+pseudorandom;
151
if (pseudorandom >= pcolors)
152
pseudorandom = pcolors-1;
154
else if (pseudorandom >= (S32)max_plasma)
155
pseudorandom = max_plasma;
158
plot(x,y,(U16)pseudorandom);
159
return((U16)pseudorandom);
163
static int _fastcall new_subD (int x1,int y1,int x2,int y2, int recur)
172
BYTE t; /* top of stack */
173
int v[16]; /* subdivided value */
174
BYTE r[16]; /* recursion level */
177
static struct sub subx, suby;
181
for (i=1;i<=recur;i++)
185
recur1 = (int)(320L >> recur);
188
ny1 = suby.v[2] = y1;
189
suby.r[0] = suby.r[2] = 0;
191
y = suby.v[1] = (ny1 + ny) >> 1;
195
if ((++plasma_check & 0x0f) == 1)
201
while (suby.r[suby.t-1] < (BYTE)recur)
203
/* 1. Create new entry at top of the stack */
204
/* 2. Copy old top value to new top value. */
205
/* This is largest y value. */
206
/* 3. Smallest y is now old mid point */
207
/* 4. Set new mid point recursion level */
208
/* 5. New mid point value is average */
209
/* of largest and smallest */
212
ny1 = suby.v[suby.t] = suby.v[suby.t-1];
213
ny = suby.v[suby.t-2];
214
suby.r[suby.t] = suby.r[suby.t-1];
215
y = suby.v[suby.t-1] = (ny1 + ny) >> 1;
216
suby.r[suby.t-1] = (BYTE)(max(suby.r[suby.t], suby.r[suby.t-2])+1);
220
nx1 = subx.v[2] = x1;
221
subx.r[0] = subx.r[2] = 0;
223
x = subx.v[1] = (nx1 + nx) >> 1;
227
while (subx.r[subx.t-1] < (BYTE)recur)
229
subx.t++; /* move the top ofthe stack up 1 */
230
nx1 = subx.v[subx.t] = subx.v[subx.t-1];
231
nx = subx.v[subx.t-2];
232
subx.r[subx.t] = subx.r[subx.t-1];
233
x = subx.v[subx.t-1] = (nx1 + nx) >> 1;
234
subx.r[subx.t-1] = (BYTE)(max(subx.r[subx.t],
235
subx.r[subx.t-2])+1);
238
if ((i = getpix(nx, y)) == 0)
239
i = adjust(nx,ny1,nx,y ,nx,ny);
241
if ((i = getpix(x, ny)) == 0)
242
i = adjust(nx1,ny,x ,ny,nx,ny);
246
if ((i = getpix(x, ny1)) == 0)
247
i = adjust(nx1,ny1,x ,ny1,nx,ny1);
249
if ((i = getpix(nx1, y)) == 0)
250
i = adjust(nx1,ny1,nx1,y ,nx1,ny);
252
plot(x,y,(U16)((v + 2) >> 2));
255
if (subx.r[subx.t-1] == (BYTE)recur) subx.t = (BYTE)(subx.t - 2);
258
if (suby.r[suby.t-1] == (BYTE)recur) suby.t = (BYTE)(suby.t - 2);
263
static void _fastcall subDivide(int x1,int y1,int x2,int y2)
267
if ((++plasma_check & 0x7f) == 1)
273
if(x2-x1<2 && y2-y1<2)
276
recur1 = (int)(320L >> recur_level);
280
if((v=getpix(x,y1)) == 0)
281
v=adjust(x1,y1,x ,y1,x2,y1);
283
if((v=getpix(x2,y)) == 0)
284
v=adjust(x2,y1,x2,y ,x2,y2);
286
if((v=getpix(x,y2)) == 0)
287
v=adjust(x1,y2,x ,y2,x2,y2);
289
if((v=getpix(x1,y)) == 0)
290
v=adjust(x1,y1,x1,y ,x1,y2);
294
plot(x,y,(U16)((i+2)>>2));
296
subDivide(x1,y1,x ,y);
297
subDivide(x ,y1,x2,y);
298
subDivide(x ,y ,x2,y2);
299
subDivide(x1,y ,x ,y2);
308
int OldPotFlag, OldPot16bit;
310
OldPotFlag=OldPot16bit=plasma_check = 0;
313
static FCODE plasmamsg[]={
315
Plasma Clouds can currently only be run in a 4-or-more-color video\n\
316
mode (and color-cycled only on VGA adapters [or EGA adapters in their\n\
317
640x350x16 mode])." };
318
stopmsg(0,plasmamsg);
321
iparmx = (int)(param[0] * 8);
322
if (parm.x <= 0.0) iparmx = 0;
323
if (parm.x >= 100) iparmx = 800;
324
param[0] = (double)iparmx / 8.0; /* let user know what was used */
325
if (param[1] < 0) param[1] = 0; /* limit parameter values */
326
if (param[1] > 1) param[1] = 1;
327
if (param[2] < 0) param[2] = 0; /* limit parameter values */
328
if (param[2] > 1) param[2] = 1;
329
if (param[3] < 0) param[3] = 0; /* limit parameter values */
330
if (param[3] > 1) param[3] = 1;
332
if ((!rflag) && param[2] == 1)
334
if (param[2] != 0 && param[2] != 1)
335
rseed = (int)param[2];
336
max_plasma = (U16)param[3]; /* max_plasma is used as a flag for potential */
340
if (pot_startdisk() >= 0)
342
/* max_plasma = (U16)(1L << 16) -1; */
345
plot = (PLOT)putpotborder;
349
OldPotFlag = potflag;
350
OldPot16bit = pot16bit;
354
max_plasma = 0; /* can't do potential (startdisk failed) */
357
plot = putcolorborder;
360
getpix = (U16(_fastcall *)(int,int))getcolor;
366
plot = putcolorborder;
369
getpix = (U16(_fastcall *)(int,int))getcolor;
374
if (colors == 256) /* set the (256-color) palette */
375
set_Plasma_palette(); /* skip this if < 256 colors */
396
pcolors = min(colors, max_colors);
397
for(n = 0; n < 4; n++)
398
rnd[n] = (U16)(1+(((rand15()/pcolors)*(pcolors-1))>>(shiftvalue-11)));
401
for(n = 0; n < 4; n++)
404
for(n = 0; n < 4; n++)
408
plot(xdots-1, 0, rnd[1]);
409
plot(xdots-1,ydots-1, rnd[2]);
410
plot( 0,ydots-1, rnd[3]);
414
subDivide(0,0,xdots-1,ydots-1);
418
while(new_subD(0,0,xdots-1,ydots-1,i)==0)
421
if (k >(int)max(xdots-1,ydots-1))
438
potflag = OldPotFlag;
439
pot16bit = OldPot16bit;
442
getpix = (U16(_fastcall *)(int,int))getcolor;
446
#define dac ((Palettetype *)dacbox)
447
static void set_Plasma_palette()
449
static Palettetype Red = { 63, 0, 0 };
450
static Palettetype Green = { 0, 63, 0 };
451
static Palettetype Blue = { 0, 0,63 };
454
if (mapdacbox || colorpreloaded) return; /* map= specified */
462
dac[i].red = (BYTE)((i*(int)Green.red + (86-i)*(int)Blue.red)/85);
463
dac[i].green = (BYTE)((i*(int)Green.green + (86-i)*(int)Blue.green)/85);
464
dac[i].blue = (BYTE)((i*(int)Green.blue + (86-i)*(int)Blue.blue)/85);
466
dac[i+85].red = (BYTE)((i*(int)Red.red + (86-i)*(int)Green.red)/85);
467
dac[i+85].green = (BYTE)((i*(int)Red.green + (86-i)*(int)Green.green)/85);
468
dac[i+85].blue = (BYTE)((i*(int)Red.blue + (86-i)*(int)Green.blue)/85);
470
dac[i+170].red = (BYTE)((i*(int)Blue.red + (86-i)*(int)Red.red)/85);
471
dac[i+170].green = (BYTE)((i*(int)Blue.green + (86-i)*(int)Red.green)/85);
472
dac[i+170].blue = (BYTE)((i*(int)Blue.blue + (86-i)*(int)Red.blue)/85);
474
dac[i].red = (BYTE)((i*Green.red + (86-i)*Blue.red)/85);
475
dac[i].green = (BYTE)((i*Green.green + (86-i)*Blue.green)/85);
476
dac[i].blue = (BYTE)((i*Green.blue + (86-i)*Blue.blue)/85);
478
dac[i+85].red = (BYTE)((i*Red.red + (86-i)*Green.red)/85);
479
dac[i+85].green = (BYTE)((i*Red.green + (86-i)*Green.green)/85);
480
dac[i+85].blue = (BYTE)((i*Red.blue + (86-i)*Green.blue)/85);
481
dac[i+170].red = (BYTE)((i*Blue.red + (86-i)*Red.red)/85);
482
dac[i+170].green = (BYTE)((i*Blue.green + (86-i)*Red.green)/85);
483
dac[i+170].blue = (BYTE)((i*Blue.blue + (86-i)*Red.blue)/85);
486
SetTgaColors(); /* TARGA 3 June 89 j mclain */
490
/***************** standalone engine for "diffusion" ********************/
492
#define RANDOM(x) (rand()%(x))
496
int xmax,ymax,xmin,ymin; /* Current maximum coordinates */
497
int border; /* Distance between release point and fractal */
498
int mode; /* Determines diffusion type: 0 = central (classic) */
499
/* 1 = falling particles */
500
/* 2 = square cavity */
501
int colorshift; /* If zero, select colors at random, otherwise shift */
502
/* the color every colorshift points */
504
int colorcount,currentcolor;
507
double cosine,sine,angle;
518
border = (int)param[0];
519
mode = (int)param[1];
520
colorshift = (int)param[2];
522
colorcount = colorshift; /* Counts down from colorshift */
523
currentcolor = 1; /* Start at color 1 (color 0 is probably invisible)*/
535
xmax = xdots / 2 + border; /* Initial box */
536
xmin = xdots / 2 - border;
537
ymax = ydots / 2 + border;
538
ymin = ydots / 2 - border;
541
xmax = xdots / 2 + border; /* Initial box */
542
xmin = xdots / 2 - border;
543
ymin = ydots - border;
547
radius = ydots - border;
549
radius = xdots - border;
551
if (resuming) /* restore worklist, if we can't the above will stay in place */
555
get_resume(sizeof(xmax),&xmax,sizeof(xmin),&xmin,sizeof(ymax),&ymax,
556
sizeof(ymin),&ymin,0);
558
get_resume(sizeof(xmax),&xmax,sizeof(xmin),&xmin,sizeof(ymax),&ymax,
559
sizeof(radius),&radius,0);
564
case 0: /* Single seed point in the center */
565
putcolor(xdots / 2, ydots / 2,currentcolor);
567
case 1: /* Line along the bottom */
568
for (i=0;i<=xdots;i++)
569
putcolor(i,ydots-1,currentcolor);
571
case 2: /* Large square that fills the screen */
573
for (i=0;i<ydots;i++){
574
putcolor(xdots/2-ydots/2 , i , currentcolor);
575
putcolor(xdots/2+ydots/2 , i , currentcolor);
576
putcolor(xdots/2-ydots/2+i , 0 , currentcolor);
577
putcolor(xdots/2-ydots/2+i , ydots-1 , currentcolor);
580
for (i=0;i<xdots;i++){
581
putcolor(0 , ydots/2-xdots/2+i , currentcolor);
582
putcolor(xdots-1 , ydots/2-xdots/2+i , currentcolor);
583
putcolor(i , ydots/2-xdots/2 , currentcolor);
584
putcolor(i , ydots/2+xdots/2 , currentcolor);
592
case 0: /* Release new point on a circle inside the box */
593
angle=2*(double)rand()/(RAND_MAX/PI);
594
FPUsincos(&angle,&sine,&cosine);
595
x = (int)(cosine*(xmax-xmin) + xdots);
596
y = (int)(sine *(ymax-ymin) + ydots);
597
x = x >> 1; /* divide by 2 */
600
case 1: /* Release new point on the line ymin somewhere between xmin
603
x=RANDOM(xmax-xmin) + (xdots-xmax+xmin)/2;
605
case 2: /* Release new point on a circle inside the box with radius
606
given by the radius variable */
607
angle=2*(double)rand()/(RAND_MAX/PI);
608
FPUsincos(&angle,&sine,&cosine);
609
x = (int)(cosine*radius + xdots);
610
y = (int)(sine *radius + ydots);
616
/* Loop as long as the point (x,y) is surrounded by color 0 */
617
/* on all eight sides */
619
while((getcolor(x+1,y+1) == 0) && (getcolor(x+1,y) == 0) &&
620
(getcolor(x+1,y-1) == 0) && (getcolor(x ,y+1) == 0) &&
621
(getcolor(x ,y-1) == 0) && (getcolor(x-1,y+1) == 0) &&
622
(getcolor(x-1,y) == 0) && (getcolor(x-1,y-1) == 0))
624
/* Erase moving point */
628
if (mode==0){ /* Make sure point is inside the box */
639
if (mode==1) /* Make sure point is on the screen below ymin, but
640
we need a 1 pixel margin because of the next random step.*/
650
/* Take one random step */
655
if ((++plasma_check & 0x7f) == 1)
660
put_resume(sizeof(xmax),&xmax,sizeof(xmin),&xmin,
661
sizeof(ymax),&ymax,sizeof(ymin),&ymin,0);
663
put_resume(sizeof(xmax),&xmax,sizeof(xmin),&xmin,
664
sizeof(ymax),&ymax,sizeof(radius),&radius,0);
670
/* Show the moving point */
672
putcolor(x,y,RANDOM(colors-1)+1);
674
} /* End of loop, now fix the point */
676
/* If we're doing colorshifting then use currentcolor, otherwise
677
pick one at random */
678
putcolor(x,y,colorshift?currentcolor:RANDOM(colors-1)+1);
680
/* If we're doing colorshifting then check to see if we need to shift*/
682
if (!--colorcount){ /* If the counter reaches zero then shift*/
683
currentcolor++; /* Increase the current color and wrap */
684
currentcolor%=colors; /* around skipping zero */
685
if (!currentcolor) currentcolor++;
686
colorcount=colorshift; /* and reset the counter */
690
/* If the new point is close to an edge, we may need to increase
691
some limits so that the limits expand to match the growing
695
case 0: if (((x+border)>xmax) || ((x-border)<xmin)
696
|| ((y-border)<ymin) || ((y+border)>ymax))
698
/* Increase box size, but not past the edge of the screen */
703
if ((ymin==0) || (xmin==0))
707
case 1: /* Decrease ymin, but not past top of screen */
713
case 2: /* Decrease the radius where points are released to stay away
714
from the fractal. It might be decreased by 1 or 2 */
715
r = sqr((float)x-xdots/2) + sqr((float)y-ydots/2);
716
if (r<=border*border)
718
while ((radius-border)*(radius-border) > r)
727
/************ standalone engine for "bifurcation" types ***************/
729
/***************************************************************/
730
/* The following code now forms a generalised Fractal Engine */
731
/* for Bifurcation fractal typeS. By rights it now belongs in */
732
/* CALCFRACT.C, but it's easier for me to leave it here ! */
734
/* Original code by Phil Wilson, hacked around by Kev Allen. */
736
/* Besides generalisation, enhancements include Periodicity */
737
/* Checking during the plotting phase (AND halfway through the */
738
/* filter cycle, if possible, to halve calc times), quicker */
739
/* floating-point calculations for the standard Verhulst type, */
740
/* and new bifurcation types (integer bifurcation, f.p & int */
741
/* biflambda - the real equivalent of complex Lambda sets - */
742
/* and f.p renditions of bifurcations of r*sin(Pi*p), which */
743
/* spurred Mitchel Feigenbaum on to discover his Number). */
745
/* To add further types, extend the fractalspecific[] array in */
746
/* usual way, with Bifurcation as the engine, and the name of */
747
/* the routine that calculates the next bifurcation generation */
748
/* as the "orbitcalc" routine in the fractalspecific[] entry. */
750
/* Bifurcation "orbitcalc" routines get called once per screen */
751
/* pixel column. They should calculate the next generation */
752
/* from the doubles Rate & Population (or the longs lRate & */
753
/* lPopulation if they use integer math), placing the result */
754
/* back in Population (or lPopulation). They should return 0 */
755
/* if all is ok, or any non-zero value if calculation bailout */
756
/* is desirable (eg in case of errors, or the series tending */
757
/* to infinity). Have fun ! */
758
/***************************************************************/
760
#define DEFAULTFILTER 1000 /* "Beauty of Fractals" recommends using 5000
761
(p.25), but that seems unnecessary. Can
762
override this value with a nonzero param1 */
764
#define SEED 0.66 /* starting value for population */
766
static int far *verhulst_array;
767
unsigned long filter_cycles;
768
static unsigned int half_time_check;
769
static long lPopulation, lRate;
770
double Population, Rate;
771
static int mono, outside_x;
774
int Bifurcation(void)
776
unsigned long array_size;
782
get_resume(sizeof(column),&column,0);
785
array_size = (iystop + 1) * sizeof(int); /* should be iystop + 1 */
786
if ((verhulst_array = (int far *) farmemalloc(array_size)) == NULL)
788
static FCODE msg[]={"Insufficient free memory for calculation."};
793
LPI = (long)(PI * fudge);
795
for (row = 0; row <= iystop; row++) /* should be iystop */
796
verhulst_array[row] = 0;
812
filter_cycles = (parm.x <= 0) ? DEFAULTFILTER : (long)parm.x;
813
half_time_check = FALSE;
814
if (periodicitycheck && (unsigned long)maxit < filter_cycles)
816
filter_cycles = (filter_cycles - maxit + 1) / 2;
817
half_time_check = TRUE;
821
linit.y = ymax - iystop*dely; /* Y-value of */
823
init.y = (double)(yymax - iystop*delyy); /* bottom pixels */
825
while (column <= ixstop)
829
farmemfree((char far *)verhulst_array);
831
put_resume(sizeof(column),&column,0);
836
lRate = xmin + column*delx;
838
Rate = (double)(xxmin + column*delxx);
839
verhulst(); /* calculate array once per column */
841
for (row = iystop; row >= 0; row--) /* should be iystop & >=0 */
844
color = verhulst_array[row];
847
else if((!color) && mono)
849
else if (color>=colors)
851
verhulst_array[row] = 0;
852
(*plot)(column,row,color); /* was row-1, but that's not right? */
856
farmemfree((char far *)verhulst_array);
860
static void verhulst() /* P. F. Verhulst (1845) */
862
unsigned int pixel_row, errors;
863
unsigned long counter;
866
lPopulation = (parm.y == 0) ? (long)(SEED*fudge) : (long)(parm.y*fudge);
868
Population = (parm.y == 0 ) ? SEED : parm.y;
870
errors = overflow = FALSE;
872
for (counter=0 ; counter < filter_cycles ; counter++)
874
errors = curfractalspecific->orbitcalc();
878
if (half_time_check) /* check for periodicity at half-time */
881
for (counter=0 ; counter < (unsigned long)maxit ; counter++)
883
errors = curfractalspecific->orbitcalc();
885
if (periodicitycheck && Bif_Periodic(counter)) break;
887
if (counter >= (unsigned long)maxit) /* if not periodic, go the distance */
889
for (counter=0 ; counter < filter_cycles ; counter++)
891
errors = curfractalspecific->orbitcalc();
897
if (periodicitycheck) Bif_Period_Init();
898
for (counter=0 ; counter < (unsigned long)maxit ; counter++)
900
errors = curfractalspecific->orbitcalc();
903
/* assign population value to Y coordinate in pixels */
905
pixel_row = iystop - (int)((lPopulation - linit.y) / dely); /* iystop */
907
pixel_row = iystop - (int)((Population - init.y) / delyy);
909
/* if it's visible on the screen, save it in the column array */
910
if (pixel_row <= (unsigned int)iystop) /* JCO 6/6/92 */
911
verhulst_array[ pixel_row ] ++;
912
if (periodicitycheck && Bif_Periodic(counter))
914
if (pixel_row <= (unsigned int)iystop) /* JCO 6/6/92 */
915
verhulst_array[ pixel_row ] --;
920
static long lBif_closenuf, lBif_savedpop; /* poss future use */
921
static double Bif_closenuf, Bif_savedpop;
922
static int Bif_savedinc;
923
static long Bif_savedand;
925
static void Bif_Period_Init()
932
lBif_closenuf = dely / 8;
937
Bif_closenuf = (double)delyy / 8.0;
941
static int _fastcall Bif_Periodic (long time) /* Bifurcation Population Periodicity Check */
942
/* Returns : 1 if periodicity found, else 0 */
944
if ((time & Bif_savedand) == 0) /* time to save a new value */
946
if (integerfractal) lBif_savedpop = lPopulation;
947
else Bif_savedpop = Population;
948
if (--Bif_savedinc == 0)
950
Bif_savedand = (Bif_savedand << 1) + 1;
954
else /* check against an old save */
958
if (labs(lBif_savedpop-lPopulation) <= lBif_closenuf)
963
if (fabs(Bif_savedpop-Population) <= Bif_closenuf)
970
/**********************************************************************/
972
/* The following are Bifurcation "orbitcalc" routines... */
974
/**********************************************************************/
976
int BifurcLambda() /* Used by lyanupov */
978
Population = Rate * Population * (1 - Population);
979
return (fabs(Population) > BIG);
983
/* Modified formulas below to generalize bifurcations. JCO 7/3/92 */
985
#define LCMPLXtrig0(arg,out) Arg1->l = (arg); ltrig0(); (out)=Arg1->l
986
#define CMPLXtrig0(arg,out) Arg1->d = (arg); dtrig0(); (out)=Arg1->d
988
int BifurcVerhulstTrig()
990
/* Population = Pop + Rate * fn(Pop) * (1 - fn(Pop)) */
993
CMPLXtrig0(tmp, tmp);
994
Population += Rate * tmp.x * (1 - tmp.x);
995
return (fabs(Population) > BIG);
998
int LongBifurcVerhulstTrig()
1001
ltmp.x = lPopulation;
1003
LCMPLXtrig0(ltmp, ltmp);
1004
ltmp.y = ltmp.x - multiply(ltmp.x,ltmp.x,bitshift);
1005
lPopulation += multiply(lRate,ltmp.y,bitshift);
1010
int BifurcStewartTrig()
1012
/* Population = (Rate * fn(Population) * fn(Population)) - 1.0 */
1015
CMPLXtrig0(tmp, tmp);
1016
Population = (Rate * tmp.x * tmp.x) - 1.0;
1017
return (fabs(Population) > BIG);
1020
int LongBifurcStewartTrig()
1023
ltmp.x = lPopulation;
1025
LCMPLXtrig0(ltmp, ltmp);
1026
lPopulation = multiply(ltmp.x,ltmp.x,bitshift);
1027
lPopulation = multiply(lPopulation,lRate, bitshift);
1028
lPopulation -= fudge;
1033
int BifurcSetTrigPi()
1035
tmp.x = Population * PI;
1037
CMPLXtrig0(tmp, tmp);
1038
Population = Rate * tmp.x;
1039
return (fabs(Population) > BIG);
1042
int LongBifurcSetTrigPi()
1045
ltmp.x = multiply(lPopulation,LPI,bitshift);
1047
LCMPLXtrig0(ltmp, ltmp);
1048
lPopulation = multiply(lRate,ltmp.x,bitshift);
1053
int BifurcAddTrigPi()
1055
tmp.x = Population * PI;
1057
CMPLXtrig0(tmp, tmp);
1058
Population += Rate * tmp.x;
1059
return (fabs(Population) > BIG);
1062
int LongBifurcAddTrigPi()
1065
ltmp.x = multiply(lPopulation,LPI,bitshift);
1067
LCMPLXtrig0(ltmp, ltmp);
1068
lPopulation += multiply(lRate,ltmp.x,bitshift);
1073
int BifurcLambdaTrig()
1075
/* Population = Rate * fn(Population) * (1 - fn(Population)) */
1078
CMPLXtrig0(tmp, tmp);
1079
Population = Rate * tmp.x * (1 - tmp.x);
1080
return (fabs(Population) > BIG);
1083
int LongBifurcLambdaTrig()
1086
ltmp.x = lPopulation;
1088
LCMPLXtrig0(ltmp, ltmp);
1089
ltmp.y = ltmp.x - multiply(ltmp.x,ltmp.x,bitshift);
1090
lPopulation = multiply(lRate,ltmp.y,bitshift);
1095
#define LCMPLXpwr(arg1,arg2,out) Arg2->l = (arg1); Arg1->l = (arg2);\
1096
lStkPwr(); Arg1++; Arg2++; (out) = Arg2->l
1101
{ /* X = (lambda * X) / (1 + X)^beta, from R.May as described in Pickover,
1102
Computers, Pattern, Chaos, and Beauty, page 153 */
1103
tmp.x = 1.0 + Population;
1104
tmp.x = pow(tmp.x, -beta); /* pow in math.h included with mpmath.h */
1105
Population = (Rate * Population) * tmp.x;
1106
return (fabs(Population) > BIG);
1112
ltmp.x = lPopulation + fudge;
1114
lparm2.x = beta * fudge;
1115
LCMPLXpwr(ltmp, lparm2, ltmp);
1116
lPopulation = multiply(lRate,lPopulation,bitshift);
1117
lPopulation = divide(lPopulation,ltmp.x,bitshift);
1122
int BifurcMaySetup()
1125
beta = (long)param[2];
1128
param[2] = (double)beta;
1130
timer(0,curfractalspecific->calctype);
1134
/* Here Endeth the Generalised Bifurcation Fractal Engine */
1136
/* END Phil Wilson's Code (modified slightly by Kev Allen et. al. !) */
1139
/******************* standalone engine for "popcorn" ********************/
1141
int popcorn() /* subset of std engine */
1148
get_resume(sizeof(start_row),&start_row,0);
1151
kbdcount=max_kbdcount;
1153
tempsqrx = ltempsqrx = 0; /* PB added this to cover weird BAILOUTs */
1154
for (row = start_row; row <= iystop; row++)
1156
reset_periodicity = 1;
1157
for (col = 0; col <= ixstop; col++)
1159
if (StandardFractal() == -1) /* interrupted */
1162
put_resume(sizeof(row),&row,0);
1165
reset_periodicity = 0;
1172
/******************* standalone engine for "lyapunov" *********************/
1173
/*** Roy Murphy [76376,721] ***/
1174
/*** revision history: ***/
1175
/*** initial version: Winter '91 ***/
1176
/*** Fall '92 integration of Nicholas Wilt's ASM speedups ***/
1177
/*** Jan 93' integration with calcfrac() yielding boundary tracing, ***/
1178
/*** tesseral, and solid guessing, and inversion, inside=nnn ***/
1179
/*** save_release behavior: ***/
1180
/*** 1730 & prior: ignores inside=, calcmode='1', (a,b)->(x,y) ***/
1181
/*** 1731: other calcmodes and inside=nnn ***/
1182
/*** 1732: the infamous axis swap: (b,a)->(x,y), ***/
1183
/*** the order parameter becomes a long int ***/
1184
/**************************************************************************/
1185
int lyaLength, lyaSeedOK;
1188
#define WES 1 /* define WES to be 0 to use Nick's lyapunov.obj */
1190
int lyapunov_cycles(double, double);
1192
int lyapunov_cycles(int, double, double, double);
1195
int lyapunov_cycles_in_c(long, double, double);
1204
if (param[1]==1) Population = (1.0+rand())/(2.0+RAND_MAX);
1205
else if (param[1]==0) {
1206
if (fabs(Population)>BIG || Population==0 || Population==1)
1207
Population = (1.0+rand())/(2.0+RAND_MAX);
1209
else Population = param[1];
1210
(*plot)(col, row, 1);
1221
/* the assembler routines don't work for a & b outside the
1222
ranges 0 < a < 4 and 0 < b < 4. So, fall back on the C
1223
routines if part of the image sticks out.
1226
color=lyapunov_cycles(a, b);
1228
if (lyaSeedOK && a>0 && b>0 && a<=4 && b<=4)
1229
color=lyapunov_cycles(filter_cycles, Population, a, b);
1231
color=lyapunov_cycles_in_c(filter_cycles, a, b);
1234
color=lyapunov_cycles_in_c(filter_cycles, a, b);
1236
if (inside>0 && color==0)
1238
else if (color>=colors)
1240
(*plot)(col, row, color);
1246
/* This routine sets up the sequence for forcing the Rate parameter
1247
to vary between the two values. It fills the array lyaRxy[] and
1248
sets lyaLength to the length of the sequence.
1250
The sequence is coded in the bit pattern in an integer.
1251
Briefly, the sequence starts with an A the leading zero bits
1252
are ignored and the remaining bit sequence is decoded. The
1253
sequence ends with a B. Not all possible sequences can be
1254
represented in this manner, but every possible sequence is
1255
either represented as itself, as a rotation of one of the
1256
representable sequences, or as the inverse of a representable
1257
sequence (swapping 0s and 1s in the array.) Sequences that
1258
are the rotation and/or inverses of another sequence will generate
1259
the same lyapunov exponents.
1261
A few examples follow:
1269
6 aaabb (this is a duplicate of 4, a rotated inverse)
1277
if ((filter_cycles=(long)param[2])==0)
1278
filter_cycles=maxit/2;
1279
lyaSeedOK = param[1]>0 && param[1]<=1 && debugflag!=90;
1284
if (save_release<1732) i &= 0x0FFFFL; /* make it a short to reporduce prior stuff*/
1287
for (t=31; t>=0; t--)
1288
if (i & (1<<t)) break;
1290
lyaRxy[lyaLength++] = (i & (1<<t)) != 0;
1291
lyaRxy[lyaLength++] = 0;
1292
if (save_release<1732) /* swap axes prior to 1732 */
1293
for (t=lyaLength; t>=0; t--)
1294
lyaRxy[t] = !lyaRxy[t];
1295
if (save_release<1731) { /* ignore inside=, stdcalcmode */
1297
if (inside==1) inside = 0;
1301
{"Sorry, inside options other than inside=nnn are not supported by the lyapunov"};
1302
stopmsg(0,(char far *)msg);
1305
if (usr_stdcalcmode == 'o') { /* Oops,lyapunov type */
1306
usr_stdcalcmode = '1'; /* doesn't use new & breaks orbits */
1312
int lyapunov_cycles_in_c(long filter_cycles, double a, double b) {
1313
int color, count, lnadjust;
1315
double lyap, total, temp;
1316
/* e10=22026.4657948 e-10=0.0000453999297625 */
1320
for (i=0; i<filter_cycles; i++) {
1321
for (count=0; count<lyaLength; count++) {
1322
Rate = lyaRxy[count] ? a : b;
1323
if (curfractalspecific->orbitcalc()) {
1329
for (i=0; i < maxit/2; i++) {
1330
for (count = 0; count < lyaLength; count++) {
1331
Rate = lyaRxy[count] ? a : b;
1332
if (curfractalspecific->orbitcalc()) {
1336
temp = fabs(Rate-2.0*Rate*Population);
1337
if ((total *= (temp))==0) {
1342
while (total > 22026.4657948) {
1343
total *= 0.0000453999297625;
1346
while (total < 0.0000453999297625) {
1347
total *= 22026.4657948;
1353
if (overflow || total <= 0 || (temp = log(total) + lnadjust) > 0)
1357
lyap = -temp/((double) lyaLength*i);
1359
lyap = 1 - exp(temp/((double) lyaLength*i));
1360
color = 1 + (int)(lyap * (colors-1));
1366
/******************* standalone engine for "cellular" ********************/
1367
/* Originally coded by Ken Shirriff.
1368
Modified beyond recognition by Jonathan Osuch.
1369
Original or'd the neighborhood, changed to sum the neighborhood
1370
Changed prompts and error messages
1372
Set the palette to some standard? CA colors
1373
Changed *cell_array to near and used dstack so put_line and get_line
1374
could be used all the time
1375
Made space bar generate next screen
1376
Increased string/rule size to 16 digits and added CA types 9/20/92
1385
#define RULELENGTH 7
1388
#define CELLULAR_DONE 10
1391
static BYTE *cell_array[2];
1393
static BYTE far *cell_array[2];
1396
S16 r, k_1, rule_digits;
1399
void abort_cellular(int err, int t)
1407
sprintf(msg,"Bad t=%d, aborting\n", t);
1408
stopmsg(0,(char far *)msg);
1413
static FCODE msg[]={"Insufficient free memory for calculation" };
1419
static FCODE msg[]={"String can be a maximum of 16 digits" };
1425
static FCODE msg[]={"Make string of 0's through 's" };
1426
msg[27] = (char)(k_1 + 48); /* turn into a character value */
1432
static FCODE msg[]={"Make Rule with 0's through 's" };
1433
msg[27] = (char)(k_1 + 48); /* turn into a character value */
1439
static FCODE msg[]={"Type must be 21, 31, 41, 51, 61, 22, 32, \
1440
42, 23, 33, 24, 25, 26, 27" };
1446
static FCODE msg[]={"Rule must be digits long" };
1447
i = rule_digits / 10;
1449
msg[14] = (char)(rule_digits + 48);
1451
msg[13] = (char)(i+48);
1452
msg[14] = (char)((rule_digits % 10) + 48);
1459
static FCODE msg[]={"Interrupted, can't resume" };
1466
if(cell_array[0] != NULL)
1468
cell_array[0] = NULL;
1470
farmemfree((char far *)cell_array[0]);
1472
if(cell_array[1] != NULL)
1474
cell_array[1] = NULL;
1476
farmemfree((char far *)cell_array[1]);
1482
S16 filled, notfilled;
1484
U16 init_string[16];
1493
set_Cellular_palette();
1495
randparam = (S32)param[0];
1496
lnnmbr = (U32)param[3];
1515
abort_cellular(TYPEKR, 0);
1520
r = (S16)(kr % 10); /* Number of nearest neighbors to sum */
1521
k = (U16)(kr / 10); /* Number of different states, k=3 has states 0,1,2 */
1522
k_1 = (S16)(k - 1); /* Highest state value, k=3 has highest state value of 2 */
1523
rule_digits = (S16)((r * 2 + 1) * k_1 + 1); /* Number of digits in the rule */
1525
if ((!rflag) && randparam == -1)
1527
if (randparam != 0 && randparam != -1) {
1529
sprintf(buf,"%.16g",n); /* # of digits in initial string */
1530
t = (S16)strlen(buf);
1531
if (t>16 || t <= 0) {
1532
abort_cellular(STRING1, 0);
1536
init_string[i] = 0; /* zero the array */
1537
t2 = (S16) ((16 - t)/2);
1538
for (i=0;i<(U16)t;i++) { /* center initial string in array */
1539
init_string[i+t2] = (U16)(buf[i] - 48); /* change character to number */
1540
if (init_string[i+t2]>(U16)k_1) {
1541
abort_cellular(STRING2, 0);
1548
if (!rflag) ++rseed;
1550
/* generate rule table from parameter 1 */
1554
/* gcc can't manage to convert a big double to an unsigned long properly. */
1555
if (param[1]>0x7fffffff) {
1556
n = (param[1]-0x7fffffff);
1562
if (n == 0) { /* calculate a random rule */
1564
for (i=1;i<(U16)rule_digits;i++) {
1570
sprintf(buf,"%.*g",rule_digits ,n);
1571
t = (S16)strlen(buf);
1572
if (rule_digits < t || t < 0) { /* leading 0s could make t smaller */
1573
abort_cellular(RULELENGTH, 0);
1576
for (i=0;i<(U16)rule_digits;i++) /* zero the table */
1578
for (i=0;i<(U16)t;i++) { /* reverse order */
1579
cell_table[i] = (U16)(buf[t-i-1] - 48); /* change character to number */
1580
if (cell_table[i]>(U16)k_1) {
1581
abort_cellular(TABLEK, 0);
1589
/* two 4096 byte arrays, at present at most 2024 + 1 bytes should be */
1590
/* needed in each array (max screen width + 1) */
1591
cell_array[0] = (BYTE *)&dstack[0]; /* dstack is in general.asm */
1592
cell_array[1] = (BYTE *)&boxy[0]; /* boxy is in general.asm */
1594
cell_array[0] = (BYTE far *)farmemalloc(ixstop+1);
1595
cell_array[1] = (BYTE far *)farmemalloc(ixstop+1);
1597
if (cell_array[0]==NULL || cell_array[1]==NULL) {
1598
abort_cellular(BAD_MEM, 0);
1602
/* nxtscreenflag toggled by space bar in fractint.c, 1 for continuous */
1603
/* 0 to stop on next screen */
1606
notfilled = (S16)(1-filled);
1607
if (resuming && !nxtscreenflag && !lstscreenflag) {
1609
get_resume(sizeof(start_row),&start_row,0);
1611
get_line(start_row,0,ixstop,cell_array[filled]);
1613
else if (nxtscreenflag && !lstscreenflag) {
1616
get_line(iystop,0,ixstop,cell_array[filled]);
1617
param[3] += iystop + 1;
1618
start_row = -1; /* after 1st iteration its = 0 */
1621
if(rflag || randparam==0 || randparam==-1){
1622
for (col=0;col<=ixstop;col++) {
1623
cell_array[filled][col] = (BYTE)(rand()%(int)k);
1625
} /* end of if random */
1628
for (col=0;col<=ixstop;col++) { /* Clear from end to end */
1629
cell_array[filled][col] = 0;
1632
for (col=(ixstop-16)/2;col<(ixstop+16)/2;col++) { /* insert initial */
1633
cell_array[filled][col] = (BYTE)init_string[i++]; /* string */
1635
} /* end of if not random */
1640
put_line(start_row,0,ixstop,cell_array[filled]);
1644
/* This section calculates the starting line when it is not zero */
1645
/* This section can't be resumed since no screen output is generated */
1646
/* calculates the (lnnmbr - 1) generation */
1647
if (lstscreenflag) { /* line number != 0 & not resuming & not continuing */
1649
for (big_row = (U32)start_row; big_row < lnnmbr; big_row++) {
1650
static FCODE msg[]={"Cellular thinking (higher start row takes longer)"};
1653
if(rflag || randparam==0 || randparam==-1){
1654
/* Use a random border */
1655
for (i=0;i<=(U16)r;i++) {
1656
cell_array[notfilled][i]=(BYTE)(rand()%(int)k);
1657
cell_array[notfilled][ixstop-i]=(BYTE)(rand()%(int)k);
1661
/* Use a zero border */
1662
for (i=0;i<=(U16)r;i++) {
1663
cell_array[notfilled][i]=0;
1664
cell_array[notfilled][ixstop-i]=0;
1668
t = 0; /* do first cell */
1669
for (twor=(U16)(r+r),i=0;i<=twor;i++)
1670
t = (S16)(t + (S16)cell_array[filled][i]);
1671
if (t>rule_digits || t<0) {
1673
abort_cellular(BAD_T, t);
1676
cell_array[notfilled][r] = (BYTE)cell_table[t];
1678
/* use a rolling sum in t */
1679
for (col=r+1;col<ixstop-r;col++) { /* now do the rest */
1680
t = (S16)(t + cell_array[filled][col+r] - cell_array[filled][col-r-1]);
1681
if (t>rule_digits || t<0) {
1683
abort_cellular(BAD_T, t);
1686
cell_array[notfilled][col] = (BYTE)cell_table[t];
1690
notfilled = (S16)(1-filled);
1693
abort_cellular(INTERUPT, 0);
1702
/* This section does all the work */
1704
for (row = start_row; row <= iystop; row++) {
1706
if(rflag || randparam==0 || randparam==-1){
1707
/* Use a random border */
1708
for (i=0;i<=(U16)r;i++) {
1709
cell_array[notfilled][i]=(BYTE)(rand()%(int)k);
1710
cell_array[notfilled][ixstop-i]=(BYTE)(rand()%(int)k);
1714
/* Use a zero border */
1715
for (i=0;i<=(U16)r;i++) {
1716
cell_array[notfilled][i]=0;
1717
cell_array[notfilled][ixstop-i]=0;
1721
t = 0; /* do first cell */
1722
for (twor=(U16)(r+r),i=0;i<=twor;i++)
1723
t = (S16)(t + (S16)cell_array[filled][i]);
1724
if (t>rule_digits || t<0) {
1726
abort_cellular(BAD_T, t);
1729
cell_array[notfilled][r] = (BYTE)cell_table[t];
1731
/* use a rolling sum in t */
1732
for (col=r+1;col<ixstop-r;col++) { /* now do the rest */
1733
t = (S16)(t + cell_array[filled][col+r] - cell_array[filled][col-r-1]);
1734
if (t>rule_digits || t<0) {
1736
abort_cellular(BAD_T, t);
1739
cell_array[notfilled][col] = (BYTE)cell_table[t];
1743
notfilled = (S16)(1-filled);
1744
put_line(row,0,ixstop,cell_array[filled]);
1746
abort_cellular(CELLULAR_DONE, 0);
1748
put_resume(sizeof(row),&row,0);
1753
param[3] += iystop + 1;
1754
start_row = -1; /* after 1st iteration its = 0 */
1757
abort_cellular(CELLULAR_DONE, 0);
1761
int CellularSetup(void)
1764
nxtscreenflag = 0; /* initialize flag */
1766
timer(0,curfractalspecific->calctype);
1770
static void set_Cellular_palette()
1772
static Palettetype Red = { 42, 0, 0 };
1773
static Palettetype Green = { 10,35,10 };
1774
static Palettetype Blue = { 13,12,29 };
1775
static Palettetype Yellow = { 60,58,18 };
1776
static Palettetype Brown = { 42,21, 0 };
1778
if (mapdacbox) return; /* map= specified */
1784
dac[1].red = Red.red;
1785
dac[1].green = Red.green;
1786
dac[1].blue = Red.blue;
1788
dac[2].red = Green.red;
1789
dac[2].green = Green.green;
1790
dac[2].blue = Green.blue;
1792
dac[3].red = Blue.red;
1793
dac[3].green = Blue.green;
1794
dac[3].blue = Blue.blue;
1796
dac[4].red = Yellow.red;
1797
dac[4].green = Yellow.green;
1798
dac[4].blue = Yellow.blue;
1800
dac[5].red = Brown.red;
1801
dac[5].green = Brown.green;
1802
dac[5].blue = Brown.blue;
1808
/* frothy basin routines */
1810
#define FROTH_BITSHIFT 28
1811
#define FROTH_D_TO_L(x) ((long)((x)*(1L<<FROTH_BITSHIFT)))
1812
#define FROTH_CLOSE 1e-6 /* seems like a good value */
1813
#define FROTH_LCLOSE FROTH_D_TO_L(FROTH_CLOSE)
1814
#define SQRT3 1.732050807568877193
1815
#define FROTH_SLOPE SQRT3
1816
#define FROTH_LSLOPE FROTH_D_TO_L(FROTH_SLOPE)
1817
#define FROTH_CRITICAL_A 1.028713768218725 /* 1.0287137682187249127 */
1818
#define froth_top_x_mapping(x) ((x)*(x)-(x)-3*fsp->fl.f.a*fsp->fl.f.a/4)
1821
static char froth3_256c[] = "froth3.map";
1822
static char froth6_256c[] = "froth6.map";
1823
static char froth3_16c[] = "froth316.map";
1824
static char froth6_16c[] = "froth616.map";
1826
struct froth_double_struct {
1843
struct froth_long_struct {
1860
struct froth_struct {
1865
union { /* This was made into a union to save 56 malloc()'ed bytes. */
1866
struct froth_double_struct f;
1867
struct froth_long_struct l;
1871
struct froth_struct *fsp=NULL; /* froth_struct pointer */
1873
/* color maps which attempt to replicate the images of James Alexander. */
1874
static void set_Froth_palette(void)
1878
if (colorstate != 0) /* 0 means dacbox matches default */
1884
if (fsp->attractors == 6)
1885
mapname = froth6_256c;
1887
mapname = froth3_256c;
1889
else /* colors >= 16 */
1891
if (fsp->attractors == 6)
1892
mapname = froth6_16c;
1894
mapname = froth3_16c;
1896
if (ValidateLuts(mapname) != 0)
1898
colorstate = 0; /* treat map it as default */
1903
int froth_setup(void)
1905
double sin_theta, cos_theta, x0, y0;
1907
sin_theta = SQRT3/2; /* sin(2*PI/3) */
1908
cos_theta = -0.5; /* cos(2*PI/3) */
1910
/* check for NULL as safety net */
1912
fsp = (struct froth_struct *)malloc(sizeof (struct froth_struct));
1916
{"Sorry, not enough memory to run the frothybasin fractal type"};
1917
stopmsg(0,(char far *)msg);
1921
/* for the all important backwards compatibility */
1922
if (save_release <= 1821) /* book version is 18.21 */
1924
/* use old release parameters */
1926
fsp->repeat_mapping = ((int)param[0] == 6 || (int)param[0] == 2); /* map 1 or 2 times (3 or 6 basins) */
1927
fsp->altcolor = (int)param[1];
1928
param[2] = 0; /* throw away any value used prior to 18.20 */
1930
fsp->attractors = !fsp->repeat_mapping ? 3 : 6;
1932
/* use old values */ /* old names */
1933
fsp->fl.f.a = 1.02871376822; /* A */
1934
fsp->fl.f.halfa = fsp->fl.f.a/2; /* A/2 */
1936
fsp->fl.f.top_x1 = -1.04368901270; /* X1MIN */
1937
fsp->fl.f.top_x2 = 1.33928675524; /* X1MAX */
1938
fsp->fl.f.top_x3 = -0.339286755220; /* XMIDT */
1939
fsp->fl.f.top_x4 = -0.339286755220; /* XMIDT */
1941
fsp->fl.f.left_x1 = 0.07639837810; /* X3MAX2 */
1942
fsp->fl.f.left_x2 = -1.11508950586; /* X2MIN2 */
1943
fsp->fl.f.left_x3 = -0.27580275066; /* XMIDL */
1944
fsp->fl.f.left_x4 = -0.27580275066; /* XMIDL */
1946
fsp->fl.f.right_x1 = 0.96729063460; /* X2MAX1 */
1947
fsp->fl.f.right_x2 = -0.22419724936; /* X3MIN1 */
1948
fsp->fl.f.right_x3 = 0.61508950585; /* XMIDR */
1949
fsp->fl.f.right_x4 = 0.61508950585; /* XMIDR */
1952
else /* use new code */
1956
fsp->repeat_mapping = (int)param[0] == 2;
1959
fsp->altcolor = (int)param[1];
1960
fsp->fl.f.a = param[2];
1962
fsp->attractors = fabs(fsp->fl.f.a) <= FROTH_CRITICAL_A ? (!fsp->repeat_mapping ? 3 : 6)
1963
: (!fsp->repeat_mapping ? 2 : 3);
1965
/* new improved values */
1966
/* 0.5 is the value that causes the mapping to reach a minimum */
1968
/* a/2 is the value that causes the y value to be invariant over the mappings */
1969
y0 = fsp->fl.f.halfa = fsp->fl.f.a/2;
1970
fsp->fl.f.top_x1 = froth_top_x_mapping(x0);
1971
fsp->fl.f.top_x2 = froth_top_x_mapping(fsp->fl.f.top_x1);
1972
fsp->fl.f.top_x3 = froth_top_x_mapping(fsp->fl.f.top_x2);
1973
fsp->fl.f.top_x4 = froth_top_x_mapping(fsp->fl.f.top_x3);
1975
/* rotate 120 degrees counter-clock-wise */
1976
fsp->fl.f.left_x1 = fsp->fl.f.top_x1 * cos_theta - y0 * sin_theta;
1977
fsp->fl.f.left_x2 = fsp->fl.f.top_x2 * cos_theta - y0 * sin_theta;
1978
fsp->fl.f.left_x3 = fsp->fl.f.top_x3 * cos_theta - y0 * sin_theta;
1979
fsp->fl.f.left_x4 = fsp->fl.f.top_x4 * cos_theta - y0 * sin_theta;
1981
/* rotate 120 degrees clock-wise */
1982
fsp->fl.f.right_x1 = fsp->fl.f.top_x1 * cos_theta + y0 * sin_theta;
1983
fsp->fl.f.right_x2 = fsp->fl.f.top_x2 * cos_theta + y0 * sin_theta;
1984
fsp->fl.f.right_x3 = fsp->fl.f.top_x3 * cos_theta + y0 * sin_theta;
1985
fsp->fl.f.right_x4 = fsp->fl.f.top_x4 * cos_theta + y0 * sin_theta;
1989
/* if 2 attractors, use same shades as 3 attractors */
1990
fsp->shades = (colors-1) / max(3,fsp->attractors);
1992
/* rqlim needs to be at least sq(1+sqrt(1+sq(a))), */
1993
/* which is never bigger than 6.93..., so we'll call it 7.0 */
1996
set_Froth_palette();
1997
/* make the best of the .map situation */
1998
orbit_color = fsp->attractors != 6 && colors >= 16 ? (fsp->shades<<1)+1 : colors-1;
2002
struct froth_long_struct tmp_l;
2004
tmp_l.a = FROTH_D_TO_L(fsp->fl.f.a);
2005
tmp_l.halfa = FROTH_D_TO_L(fsp->fl.f.halfa);
2007
tmp_l.top_x1 = FROTH_D_TO_L(fsp->fl.f.top_x1);
2008
tmp_l.top_x2 = FROTH_D_TO_L(fsp->fl.f.top_x2);
2009
tmp_l.top_x3 = FROTH_D_TO_L(fsp->fl.f.top_x3);
2010
tmp_l.top_x4 = FROTH_D_TO_L(fsp->fl.f.top_x4);
2012
tmp_l.left_x1 = FROTH_D_TO_L(fsp->fl.f.left_x1);
2013
tmp_l.left_x2 = FROTH_D_TO_L(fsp->fl.f.left_x2);
2014
tmp_l.left_x3 = FROTH_D_TO_L(fsp->fl.f.left_x3);
2015
tmp_l.left_x4 = FROTH_D_TO_L(fsp->fl.f.left_x4);
2017
tmp_l.right_x1 = FROTH_D_TO_L(fsp->fl.f.right_x1);
2018
tmp_l.right_x2 = FROTH_D_TO_L(fsp->fl.f.right_x2);
2019
tmp_l.right_x3 = FROTH_D_TO_L(fsp->fl.f.right_x3);
2020
tmp_l.right_x4 = FROTH_D_TO_L(fsp->fl.f.right_x4);
2027
void froth_cleanup(void)
2031
/* set to NULL as a flag that froth_cleanup() has been called */
2036
/* Froth Fractal type */
2037
int calcfroth(void) /* per pixel 1/2/g, called with row & col set */
2039
int found_attractor=0;
2046
{ /* error occured allocating memory for fsp */
2053
(*plot) (col, row, showdot%colors);
2054
if (!integerfractal) /* fp mode */
2067
while (!found_attractor
2068
&& ((tempsqrx=sqr(old.x)) + (tempsqry=sqr(old.y)) < rqlim)
2069
&& (coloriter < maxit))
2071
/* simple formula: z = z^2 + conj(z*(-1+ai)) */
2072
/* but it's the attractor that makes this so interesting */
2073
new.x = tempsqrx - tempsqry - old.x - fsp->fl.f.a*old.y;
2074
old.y += (old.x+old.x)*old.y - fsp->fl.f.a*old.x;
2076
if (fsp->repeat_mapping)
2078
new.x = sqr(old.x) - sqr(old.y) - old.x - fsp->fl.f.a*old.y;
2079
old.y += (old.x+old.x)*old.y - fsp->fl.f.a*old.x;
2088
plot_orbit(old.x, old.y, -1);
2091
if (fabs(fsp->fl.f.halfa-old.y) < FROTH_CLOSE
2092
&& old.x >= fsp->fl.f.top_x1 && old.x <= fsp->fl.f.top_x2)
2094
if ((!fsp->repeat_mapping && fsp->attractors == 2)
2095
|| (fsp->repeat_mapping && fsp->attractors == 3))
2096
found_attractor = 1;
2097
else if (old.x <= fsp->fl.f.top_x3)
2098
found_attractor = 1;
2099
else if (old.x >= fsp->fl.f.top_x4) {
2100
if (!fsp->repeat_mapping)
2101
found_attractor = 1;
2103
found_attractor = 2;
2106
else if (fabs(FROTH_SLOPE*old.x - fsp->fl.f.a - old.y) < FROTH_CLOSE
2107
&& old.x <= fsp->fl.f.right_x1 && old.x >= fsp->fl.f.right_x2)
2109
if (!fsp->repeat_mapping && fsp->attractors == 2)
2110
found_attractor = 2;
2111
else if (fsp->repeat_mapping && fsp->attractors == 3)
2112
found_attractor = 3;
2113
else if (old.x >= fsp->fl.f.right_x3) {
2114
if (!fsp->repeat_mapping)
2115
found_attractor = 2;
2117
found_attractor = 4;
2119
else if (old.x <= fsp->fl.f.right_x4) {
2120
if (!fsp->repeat_mapping)
2121
found_attractor = 3;
2123
found_attractor = 6;
2126
else if (fabs(-FROTH_SLOPE*old.x - fsp->fl.f.a - old.y) < FROTH_CLOSE
2127
&& old.x <= fsp->fl.f.left_x1 && old.x >= fsp->fl.f.left_x2)
2129
if (!fsp->repeat_mapping && fsp->attractors == 2)
2130
found_attractor = 2;
2131
else if (fsp->repeat_mapping && fsp->attractors == 3)
2132
found_attractor = 2;
2133
else if (old.x >= fsp->fl.f.left_x3) {
2134
if (!fsp->repeat_mapping)
2135
found_attractor = 3;
2137
found_attractor = 5;
2139
else if (old.x <= fsp->fl.f.left_x4) {
2140
if (!fsp->repeat_mapping)
2141
found_attractor = 2;
2143
found_attractor = 3;
2148
else /* integer mode */
2153
lold.x = (long)(tmp.x * fudge);
2154
lold.y = (long)(tmp.y * fudge);
2162
while (!found_attractor && ((lmagnitud = (ltempsqrx=lsqr(lold.x)) + (ltempsqry=lsqr(lold.y))) < llimit)
2163
&& (lmagnitud >= 0) && (coloriter < maxit))
2165
/* simple formula: z = z^2 + conj(z*(-1+ai)) */
2166
/* but it's the attractor that makes this so interesting */
2167
lnew.x = ltempsqrx - ltempsqry - lold.x - multiply(fsp->fl.l.a,lold.y,bitshift);
2168
lold.y += (multiply(lold.x,lold.y,bitshift)<<1) - multiply(fsp->fl.l.a,lold.x,bitshift);
2170
if (fsp->repeat_mapping)
2172
lmagnitud = (ltempsqrx=lsqr(lold.x)) + (ltempsqry=lsqr(lold.y));
2173
if ((lmagnitud > llimit) || (lmagnitud < 0))
2175
lnew.x = ltempsqrx - ltempsqry - lold.x - multiply(fsp->fl.l.a,lold.y,bitshift);
2176
lold.y += (multiply(lold.x,lold.y,bitshift)<<1) - multiply(fsp->fl.l.a,lold.x,bitshift);
2184
iplot_orbit(lold.x, lold.y, -1);
2187
if (labs(fsp->fl.l.halfa-lold.y) < FROTH_LCLOSE
2188
&& lold.x > fsp->fl.l.top_x1 && lold.x < fsp->fl.l.top_x2)
2190
if ((!fsp->repeat_mapping && fsp->attractors == 2)
2191
|| (fsp->repeat_mapping && fsp->attractors == 3))
2192
found_attractor = 1;
2193
else if (lold.x <= fsp->fl.l.top_x3)
2194
found_attractor = 1;
2195
else if (lold.x >= fsp->fl.l.top_x4) {
2196
if (!fsp->repeat_mapping)
2197
found_attractor = 1;
2199
found_attractor = 2;
2202
else if (labs(multiply(FROTH_LSLOPE,lold.x,bitshift)-fsp->fl.l.a-lold.y) < FROTH_LCLOSE
2203
&& lold.x <= fsp->fl.l.right_x1 && lold.x >= fsp->fl.l.right_x2)
2205
if (!fsp->repeat_mapping && fsp->attractors == 2)
2206
found_attractor = 2;
2207
else if (fsp->repeat_mapping && fsp->attractors == 3)
2208
found_attractor = 3;
2209
else if (lold.x >= fsp->fl.l.right_x3) {
2210
if (!fsp->repeat_mapping)
2211
found_attractor = 2;
2213
found_attractor = 4;
2215
else if (lold.x <= fsp->fl.l.right_x4) {
2216
if (!fsp->repeat_mapping)
2217
found_attractor = 3;
2219
found_attractor = 6;
2222
else if (labs(multiply(-FROTH_LSLOPE,lold.x,bitshift)-fsp->fl.l.a-lold.y) < FROTH_LCLOSE)
2224
if (!fsp->repeat_mapping && fsp->attractors == 2)
2225
found_attractor = 2;
2226
else if (fsp->repeat_mapping && fsp->attractors == 3)
2227
found_attractor = 2;
2228
else if (lold.x >= fsp->fl.l.left_x3) {
2229
if (!fsp->repeat_mapping)
2230
found_attractor = 3;
2232
found_attractor = 5;
2234
else if (lold.x <= fsp->fl.l.left_x4) {
2235
if (!fsp->repeat_mapping)
2236
found_attractor = 2;
2238
found_attractor = 3;
2246
realcoloriter = coloriter;
2247
if ((kbdcount -= abs((int)realcoloriter)) <= 0)
2251
kbdcount = max_kbdcount;
2254
/* inside - Here's where non-palette based images would be nice. Instead, */
2255
/* we'll use blocks of (colors-1)/3 or (colors-1)/6 and use special froth */
2256
/* color maps in attempt to replicate the images of James Alexander. */
2257
if (found_attractor)
2263
if (coloriter > fsp->shades)
2264
coloriter = fsp->shades;
2267
coloriter = fsp->shades * coloriter / maxit;
2270
coloriter += fsp->shades * (found_attractor-1);
2272
else if (colors >= 16)
2273
{ /* only alternate coloring scheme available for 16 colors */
2276
/* Trying to make a better 16 color distribution. */
2277
/* Since their are only a few possiblities, just handle each case. */
2278
/* This is a mostly guess work here. */
2279
lshade = (coloriter<<16)/maxit;
2280
if (fsp->attractors != 6) /* either 2 or 3 attractors */
2282
if (lshade < 2622) /* 0.04 */
2284
else if (lshade < 10486) /* 0.16 */
2286
else if (lshade < 23593) /* 0.36 */
2288
else if (lshade < 41943L) /* 0.64 */
2292
coloriter += 5 * (found_attractor-1);
2294
else /* 6 attractors */
2296
if (lshade < 10486) /* 0.16 */
2300
coloriter += 2 * (found_attractor-1);
2303
else /* use a color corresponding to the attractor */
2304
coloriter = found_attractor;
2305
oldcoloriter = coloriter;
2307
else /* outside, or inside but didn't get sucked in by attractor. */
2310
color = abs((int)(coloriter));
2312
(*plot)(col, row, color);
2318
These last two froth functions are for the orbit-in-window feature.
2319
Normally, this feature requires StandardFractal, but since it is the
2320
attractor that makes the frothybasin type so unique, it is worth
2321
putting in as a stand-alone.
2324
int froth_per_pixel(void)
2326
if (!integerfractal) /* fp mode */
2330
tempsqrx=sqr(old.x);
2331
tempsqry=sqr(old.y);
2333
else /* integer mode */
2337
ltempsqrx = multiply(lold.x, lold.x, bitshift);
2338
ltempsqry = multiply(lold.y, lold.y, bitshift);
2343
int froth_per_orbit(void)
2345
if (!integerfractal) /* fp mode */
2347
new.x = tempsqrx - tempsqry - old.x - fsp->fl.f.a*old.y;
2348
new.y = 2.0*old.x*old.y - fsp->fl.f.a*old.x + old.y;
2349
if (fsp->repeat_mapping)
2352
new.x = sqr(old.x) - sqr(old.y) - old.x - fsp->fl.f.a*old.y;
2353
new.y = 2.0*old.x*old.y - fsp->fl.f.a*old.x + old.y;
2356
if ((tempsqrx=sqr(new.x)) + (tempsqry=sqr(new.y)) >= rqlim)
2360
else /* integer mode */
2362
lnew.x = ltempsqrx - ltempsqry - lold.x - multiply(fsp->fl.l.a,lold.y,bitshift);
2363
lnew.y = lold.y + (multiply(lold.x,lold.y,bitshift)<<1) - multiply(fsp->fl.l.a,lold.x,bitshift);
2364
if (fsp->repeat_mapping)
2366
if ((ltempsqrx=lsqr(lnew.x)) + (ltempsqry=lsqr(lnew.y)) >= llimit)
2369
lnew.x = ltempsqrx - ltempsqry - lold.x - multiply(fsp->fl.l.a,lold.y,bitshift);
2370
lnew.y = lold.y + (multiply(lold.x,lold.y,bitshift)<<1) - multiply(fsp->fl.l.a,lold.x,bitshift);
2372
if ((ltempsqrx=lsqr(lnew.x)) + (ltempsqry=lsqr(lnew.y)) >= llimit)