File: common\evolve.c
1 #include "port.h"
2 #include "prototyp.h"
3 #include "fractype.h"
4 #include "helpdefs.h"
5 #define PARMBOX 128
6 U16 gene_handle = 0;
7
8 /* px and py are coordinates in the parameter grid (small images on screen) */
9 /* evolving = flag, gridsz = dimensions of image grid (gridsz x gridsz) */
10 int px,py,evolving,gridsz;
11 #define MAXGRIDSZ 51 /* This is arbitrary, = 1024/20 */
12 static int far ecountbox[MAXGRIDSZ][MAXGRIDSZ];
13
14 unsigned int this_gen_rseed;
15 /* used to replay random sequences to obtain correct values when selecting a
16 seed image for next generation */
17
18 double opx,opy,newopx,newopy,paramrangex,paramrangey,dpx,dpy,fiddlefactor;
19 double fiddle_reduction;
20 double parmzoom;
21 char odpx,odpy,newodpx,newodpy;
22 /* offset for discrete parameters x and y..*/
23 /* used for things like inside or outside types, bailout tests, trig fn etc */
24 /* variation factors, opx,opy, paramrangex/y dpx, dpy.. used in field mapping
25 for smooth variation across screen. opx =offset param x, dpx = delta param
26 per image, paramrangex = variation across grid of param ...likewise for py */
27 /* fiddlefactor is amount of random mutation used in random modes ,
28 fiddle_reduction is used to decrease fiddlefactor from one generation to the
29 next to eventually produce a stable population */
30
31 U16 prmboxhandle = 0;
32 U16 imgboxhandle = 0;
33 int prmboxcount,imgboxcount;
34 U16 oldhistory_handle = 0;
35 char s_random[] = "random";
36 char s_spread[] = "spread";
37 char s_xplusy[] = "x+y";
38 char s_xminusy[] = "x-y";
39
40 struct phistory_info /* for saving evolution data of center image */
41 {
42 double param0;
43 double param1;
44 double param2;
45 double param3;
46 double param4;
47 double param5;
48 double param6;
49 double param7;
50 double param8;
51 double param9;
52 int inside;
53 int outside;
54 int decomp0;
55 double invert0;
56 double invert1;
57 double invert2;
58 BYTE trigndx0;
59 BYTE trigndx1;
60 BYTE trigndx2;
61 BYTE trigndx3;
62 int bailoutest;
63 };
64
65 typedef struct phistory_info PARAMHIST;
66
67 void param_history(int mode);
68 void varydbl(GENEBASE gene[],int randval,int i);
69 int varyint( int randvalue, int limit, int mode);
70 int wrapped_positive_varyint( int randvalue, int limit, int mode );
71 void varyinside(GENEBASE gene[], int randval, int i);
72 void varyoutside(GENEBASE gene[], int randval, int i);
73 void varypwr2(GENEBASE gene[], int randval, int i);
74 void varytrig(GENEBASE gene[], int randval, int i);
75 void varybotest(GENEBASE gene[], int randval, int i);
76 void varyinv(GENEBASE gene[], int randval, int i);
77 int explore_check(void);
78 void spiralmap(int);
79 static void set_random(int);
80 void set_mutation_level(int);
81 void SetupParamBox(void);
82 void ReleaseParamBox(void);
83
84 void initgene(void) /* set up pointers and mutation params for all usable image
85 control variables in fractint... revise as necessary when
86 new vars come along... dont forget to increment NUMGENES
87 (in fractint.h ) as well */
88 {
89 int i = 0;
90 /* 0 = dont vary, 1= with x axis, 2 = with y */
91 /* 3 = with x+y, 4 = with x-y, 5 = random, 6 = weighted random */
92 /* Use only 15 letters below: 123456789012345 */
93 static FCODE s_Param0[] = {"Param 1 real"};
94 static FCODE s_Param1[] = {"Param 1 imag"};
95 static FCODE s_Param2[] = {"Param 2 real"};
96 static FCODE s_Param3[] = {"Param 2 imag"};
97 static FCODE s_Param4[] = {"Param 3 real"};
98 static FCODE s_Param5[] = {"Param 3 imag"};
99 static FCODE s_Param6[] = {"Param 4 real"};
100 static FCODE s_Param7[] = {"Param 4 imag"};
101 static FCODE s_Param8[] = {"Param 5 real"};
102 static FCODE s_Param9[] = {"Param 5 imag"};
103 static FCODE s_inside[] = {"inside colour"};
104 static FCODE s_outside[] = {"outside colour"};
105 static FCODE s_decomp[] = {"decomposition"};
106 static FCODE s_trigfn1[] = {"trig function 1"};
107 static FCODE s_trigfn2[] = {"trig fn 2"};
108 static FCODE s_trigfn3[] = {"trig fn 3"};
109 static FCODE s_trigfn4[] = {"trig fn 4"};
110 static FCODE s_botest[] = {"bailout test"};
111 static FCODE s_invertr[] = {"invert radius"};
112 static FCODE s_invertx[] = {"invert center x"};
113 static FCODE s_inverty[] = {"invert center y"};
114
115 GENEBASE gene[NUMGENES] = {
116 { ¶m[0], varydbl, 5, "",1 },
117 { ¶m[1], varydbl, 5, "",1 },
118 { ¶m[2], varydbl, 0, "",1 },
119 { ¶m[3], varydbl, 0, "",1 },
120 { ¶m[4], varydbl, 0, "",1 },
121 { ¶m[5], varydbl, 0, "",1 },
122 { ¶m[6], varydbl, 0, "",1 },
123 { ¶m[7], varydbl, 0, "",1 },
124 { ¶m[8], varydbl, 0, "",1 },
125 { ¶m[9], varydbl, 0, "",1 },
126 { &inside, varyinside, 0, "",2 },
127 { &outside, varyoutside, 0, "",3 },
128 { &decomp[0], varypwr2, 0, "",4 },
129 { &inversion[0],varyinv, 0, "",7 },
130 { &inversion[1],varyinv, 0, "",7 },
131 { &inversion[2],varyinv, 0, "",7 },
132 { &trigndx[0], varytrig, 0, "",5 },
133 { &trigndx[1], varytrig, 0, "",5 },
134 { &trigndx[2], varytrig, 0, "",5 },
135 { &trigndx[3], varytrig, 0, "",5 },
136 { &bailoutest, varybotest, 0, "",6 }
137 };
138 i = -1;
139 far_strcpy(gene[++i].name, s_Param0); /* name of var for menus */
140 far_strcpy(gene[++i].name, s_Param1);
141 far_strcpy(gene[++i].name, s_Param2);
142 far_strcpy(gene[++i].name, s_Param3);
143 far_strcpy(gene[++i].name, s_Param4);
144 far_strcpy(gene[++i].name, s_Param5);
145 far_strcpy(gene[++i].name, s_Param6);
146 far_strcpy(gene[++i].name, s_Param7);
147 far_strcpy(gene[++i].name, s_Param8);
148 far_strcpy(gene[++i].name, s_Param9);
149 far_strcpy(gene[++i].name, s_inside);
150 far_strcpy(gene[++i].name, s_outside);
151 far_strcpy(gene[++i].name, s_decomp);
152 far_strcpy(gene[++i].name, s_invertr);
153 far_strcpy(gene[++i].name, s_invertx);
154 far_strcpy(gene[++i].name, s_inverty);
155 far_strcpy(gene[++i].name, s_trigfn1);
156 far_strcpy(gene[++i].name, s_trigfn2);
157 far_strcpy(gene[++i].name, s_trigfn3);
158 far_strcpy(gene[++i].name, s_trigfn4);
159 far_strcpy(gene[++i].name, s_botest);
160
161 if (gene_handle == 0)
162 gene_handle = MemoryAlloc((U16)sizeof(gene),1L,FARMEM);
163 MoveToMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
164 }
165
166 void param_history(int mode)
167 { /* mode = 0 for save old history,
168 mode = 1 for restore old history */
169
170 PARAMHIST oldhistory;
171
172 if (oldhistory_handle == 0)
173 oldhistory_handle = MemoryAlloc((U16)sizeof(oldhistory),1L,FARMEM);
174
175 if (mode == 0) { /* save the old parameter history */
176 oldhistory.param0 = param[0];
177 oldhistory.param1 = param[1];
178 oldhistory.param2 = param[2];
179 oldhistory.param3 = param[3];
180 oldhistory.param4 = param[4];
181 oldhistory.param5 = param[5];
182 oldhistory.param6 = param[6];
183 oldhistory.param7 = param[7];
184 oldhistory.param8 = param[8];
185 oldhistory.param9 = param[9];
186 oldhistory.inside = inside;
187 oldhistory.outside = outside;
188 oldhistory.decomp0 = decomp[0];
189 oldhistory.invert0 = inversion[0];
190 oldhistory.invert1 = inversion[1];
191 oldhistory.invert2 = inversion[2];
192 oldhistory.trigndx0 = trigndx[0];
193 oldhistory.trigndx1 = trigndx[1];
194 oldhistory.trigndx2 = trigndx[2];
195 oldhistory.trigndx3 = trigndx[3];
196 oldhistory.bailoutest = bailoutest;
197 MoveToMemory((BYTE *)&oldhistory, (U16)sizeof(oldhistory), 1L, 0L, oldhistory_handle);
198 }
199
200 if (mode == 1) { /* restore the old parameter history */
201 MoveFromMemory((BYTE *)&oldhistory, (U16)sizeof(oldhistory), 1L, 0L, oldhistory_handle);
202 param[0] = oldhistory.param0;
203 param[1] = oldhistory.param1;
204 param[2] = oldhistory.param2;
205 param[3] = oldhistory.param3;
206 param[4] = oldhistory.param4;
207 param[5] = oldhistory.param5;
208 param[6] = oldhistory.param6;
209 param[7] = oldhistory.param7;
210 param[8] = oldhistory.param8;
211 param[9] = oldhistory.param9;
212 inside = oldhistory.inside;
213 outside = oldhistory.outside;
214 decomp[0] = oldhistory.decomp0;
215 inversion[0] = oldhistory.invert0;
216 inversion[1] = oldhistory.invert1;
217 inversion[2] = oldhistory.invert2;
218 invert = (inversion[0] == 0.0) ? 0 : 3 ;
219 trigndx[0] = oldhistory.trigndx0;
220 trigndx[1] = oldhistory.trigndx1;
221 trigndx[2] = oldhistory.trigndx2;
222 trigndx[3] = oldhistory.trigndx3;
223 bailoutest = oldhistory.bailoutest;
224 }
225 }
226
227 void varydbl(GENEBASE gene[],int randval,int i) /* routine to vary doubles */
228 {
229 int lclpy = gridsz - py - 1;
230 switch(gene[i].mutate) {
231 default:
232 case 0:
233 break;
234 case 1:
235 *(double *)gene[i].addr = px * dpx + opx; /*paramspace x coord * per view delta px + offset */
236 break;
237 case 2:
238 *(double *)gene[i].addr = lclpy * dpy + opy; /*same for y */
239 break;
240 case 3:
241 *(double *)gene[i].addr = px*dpx+opx +(lclpy*dpy)+opy; /*and x+y */
242 break;
243 case 4:
244 *(double *)gene[i].addr = (px*dpx+opx)-(lclpy*dpy+opy); /*and x-y*/
245 break;
246 case 5:
247 *(double *)gene[i].addr += (((double)randval / RAND_MAX) * 2 * fiddlefactor) - fiddlefactor;
248 break;
249 case 6: /* weighted random mutation, further out = further change */
250 {
251 int mid = gridsz /2;
252 double radius = sqrt( sqr(px - mid) + sqr(lclpy - mid) );
253 *(double *)gene[i].addr += ((((double)randval / RAND_MAX) * 2 * fiddlefactor) - fiddlefactor) * radius;
254 }
255 break;
256 }
257 return;
258 }
259
260 int varyint( int randvalue, int limit, int mode)
261 {
262 int ret = 0;
263 int lclpy = gridsz - py - 1;
264 switch(mode) {
265 default:
266 case 0:
267 break;
268 case 1: /* vary with x */
269 ret = (odpx+px)%limit;
270 break;
271 case 2: /* vary with y */
272 ret = (odpy+lclpy)%limit;
273 break;
274 case 3: /* vary with x+y */
275 ret = (odpx+px+odpy+lclpy)%limit;
276 break;
277 case 4: /* vary with x-y */
278 ret = (odpx+px)-(odpy+lclpy)%limit;
279 break;
280 case 5: /* random mutation */
281 ret = randvalue % limit;
282 break;
283 case 6: /* weighted random mutation, further out = further change */
284 {
285 int mid = gridsz /2;
286 double radius = sqrt( sqr(px - mid) + sqr(lclpy - mid) );
287 ret = (int)((((randvalue / RAND_MAX) * 2 * fiddlefactor) - fiddlefactor) * radius);
288 ret %= limit;
289 }
290 break;
291 }
292 return(ret);
293 }
294
295 int wrapped_positive_varyint( int randvalue, int limit, int mode )
296 {
297 int i;
298 i = varyint(randvalue,limit,mode);
299 if (i < 0)
300 return(limit + i);
301 else
302 return(i);
303 }
304
305 void varyinside(GENEBASE gene[], int randval, int i)
306 {
307 int choices[9]={-59,-60,-61,-100,-101,-102,-103,-104,-1};
308 if (gene[i].mutate)
309 *(int*)gene[i].addr=choices[wrapped_positive_varyint(randval,9,gene[i].mutate)];
310 return;
311 }
312
313 void varyoutside(GENEBASE gene[], int randval, int i)
314 {
315 int choices[8]={-1,-2,-3,-4,-5,-6,-7,-8};
316 if (gene[i].mutate)
317 *(int*)gene[i].addr=choices[wrapped_positive_varyint(randval,8,gene[i].mutate)];
318 return;
319 }
320
321 void varybotest(GENEBASE gene[], int randval, int i)
322 {
323 int choices[7]={Mod, Real, Imag, Or, And, Manh, Manr};
324 if (gene[i].mutate) {
325 *(int*)gene[i].addr=choices[wrapped_positive_varyint(randval,7,gene[i].mutate)];
326 /* move this next bit to varybot where it belongs */
327 setbailoutformula(bailoutest);
328 }
329 return;
330 }
331
332 void varypwr2(GENEBASE gene[], int randval, int i)
333 {
334 int choices[9]={0,2,4,8,16,32,64,128,256};
335 if (gene[i].mutate)
336 *(int*)gene[i].addr=choices[wrapped_positive_varyint(randval,9,gene[i].mutate)];
337 return;
338 }
339
340 void varytrig(GENEBASE gene[], int randval, int i)
341 {
342 if (gene[i].mutate)
343 /* Changed following to BYTE since trigfn is an array of BYTEs and if one */
344 /* of the functions isn't varied, it's value was being zeroed by the high */
345 /* BYTE of the preceeding function. JCO 2 MAY 2001 */
346 *(BYTE*)gene[i].addr=(BYTE)wrapped_positive_varyint(randval,numtrigfn,gene[i].mutate);
347 /* replaced '30' with numtrigfn, set in prompts1.c */
348 set_trig_pointers(5); /*set all trig ptrs up*/
349 return;
350 }
351
352 void varyinv(GENEBASE gene[], int randval, int i)
353 {
354 if (gene[i].mutate)
355 varydbl(gene,randval,i);
356 invert = (inversion[0] == 0.0) ? 0 : 3 ;
357 }
358
359 #define LOADCHOICES(X) {\
360 static FCODE tmp[] = { X };\
361 far_strcpy(ptr,(char far *)tmp);\
362 choices[++k]= ptr;\
363 ptr += sizeof(tmp);\
364 }
365
366 /* --------------------------------------------------------------------- */
367 /*
368 get_evolve_params() is called from FRACTINT.C whenever the 'ctrl_e' key
369 is pressed. Return codes are:
370 -1 routine was ESCAPEd - no need to re-generate the images
371 0 minor variable changed. No need to re-generate the image.
372 1 major parms changed. Re-generate the images.
373 */
374 int get_the_rest(void)
375 {
376 char *evolvmodes[]={s_no,s_x,s_y,s_xplusy,s_xminusy,s_random,s_spread};
377 static FCODE o_hdg[]={"Variable tweak central 2 of 2"};
378 int i,k,num, numtrig;
379 char hdg[sizeof(o_hdg)];
380 char far *choices[20];
381 char far *ptr;
382 struct fullscreenvalues uvalues[20];
383 GENEBASE gene[NUMGENES];
384
385 far_strcpy(hdg,o_hdg);
386 ptr = (char far *)MK_FP(extraseg,0);
387
388 MoveFromMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
389
390 numtrig = (curfractalspecific->flags >> 6) & 7;
391 if(fractype==FORMULA || fractype==FFORMULA ) {
392 numtrig = maxfn;
393 }
394
395 choose_vars_restart:
396
397 k = -1;
398 for (num = MAXPARAMS; num < (NUMGENES - 5); num++) {
399 choices[++k]=gene[num].name;
400 uvalues[k].type = 'l';
401 uvalues[k].uval.ch.vlen = 7;
402 uvalues[k].uval.ch.llen = 7;
403 uvalues[k].uval.ch.list = evolvmodes;
404 uvalues[k].uval.ch.val = gene[num].mutate;
405 }
406
407 for (num = (NUMGENES - 5); num < (NUMGENES - 5 + numtrig); num++) {
408 choices[++k]=gene[num].name;
409 uvalues[k].type = 'l';
410 uvalues[k].uval.ch.vlen = 7;
411 uvalues[k].uval.ch.llen = 7;
412 uvalues[k].uval.ch.list = evolvmodes;
413 uvalues[k].uval.ch.val = gene[num].mutate;
414 }
415
416 if (curfractalspecific->calctype == StandardFractal &&
417 (curfractalspecific->flags & BAILTEST) ) {
418 choices[++k]=gene[NUMGENES - 1].name;
419 uvalues[k].type = 'l';
420 uvalues[k].uval.ch.vlen = 7;
421 uvalues[k].uval.ch.llen = 7;
422 uvalues[k].uval.ch.list = evolvmodes;
423 uvalues[k].uval.ch.val = gene[NUMGENES - 1].mutate;
424 }
425
426 LOADCHOICES("");
427 uvalues[k].type = '*';
428 LOADCHOICES("Press F2 to set all to off");
429 uvalues[k].type ='*';
430 LOADCHOICES("Press F3 to set all on");
431 uvalues[k].type = '*';
432 LOADCHOICES("Press F4 to randomize all");
433 uvalues[k].type = '*';
434
435 i = fullscreen_prompt(hdg,k+1,choices,uvalues,28,NULL);
436
437 switch(i) {
438 case F2: /* set all off */
439 for (num = MAXPARAMS; num < NUMGENES; num++)
440 gene[num].mutate = 0;
441 goto choose_vars_restart;
442 case F3: /* set all on..alternate x and y for field map */
443 for (num = MAXPARAMS; num < NUMGENES; num ++ )
444 gene[num].mutate = (char)((num % 2) + 1);
445 goto choose_vars_restart;
446 case F4: /* Randomize all */
447 for (num =MAXPARAMS; num < NUMGENES; num ++ )
448 gene[num].mutate = (char)(rand() % 6);
449 goto choose_vars_restart;
450 case -1:
451 return(-1);
452 default:
453 break;
454 }
455
456 /* read out values */
457 k = -1;
458 for ( num = MAXPARAMS; num < (NUMGENES - 5); num++)
459 gene[num].mutate = (char)(uvalues[++k].uval.ch.val);
460
461 for (num = (NUMGENES - 5); num < (NUMGENES - 5 + numtrig); num++)
462 gene[num].mutate = (char)(uvalues[++k].uval.ch.val);
463
464 if (curfractalspecific->calctype == StandardFractal &&
465 (curfractalspecific->flags & BAILTEST) )
466 gene[NUMGENES - 1].mutate = (char)(uvalues[++k].uval.ch.val);
467
468 MoveToMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
469 return(1); /* if you were here, you want to regenerate */
470 }
471
472 int get_variations(void)
473 {
474 char *evolvmodes[]={s_no,s_x,s_y,s_xplusy,s_xminusy,s_random,s_spread};
475 static FCODE o_hdg[]={"Variable tweak central 1 of 2"};
476 int i,k,num, numparams;
477 char hdg[sizeof(o_hdg)];
478 char far *choices[20];
479 char far *ptr;
480 struct fullscreenvalues uvalues[20];
481 GENEBASE gene[NUMGENES];
482 int firstparm = 0;
483 int lastparm = MAXPARAMS;
484 int chngd = -1;
485
486 far_strcpy(hdg,o_hdg);
487 ptr = (char far *)MK_FP(extraseg,0);
488
489 MoveFromMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
490
491 if(fractype == FORMULA || fractype == FFORMULA) {
492 if(uses_p1) /* set first parameter */
493 firstparm = 0;
494 else if(uses_p2)
495 firstparm = 2;
496 else if(uses_p3)
497 firstparm = 4;
498 else if(uses_p4)
499 firstparm = 6;
500 else
501 firstparm = 8; /* uses_p5 or no parameter */
502
503 if(uses_p5) /* set last parameter */
504 lastparm = 10;
505 else if(uses_p4)
506 lastparm = 8;
507 else if(uses_p3)
508 lastparm = 6;
509 else if(uses_p2)
510 lastparm = 4;
511 else
512 lastparm = 2; /* uses_p1 or no parameter */
513 }
514
515 numparams = 0;
516 for (i = firstparm; i < lastparm; i++)
517 {
518 if (typehasparm(julibrot?neworbittype:fractype,i,NULL)==0) {
519 if(fractype == FORMULA || fractype == FFORMULA)
520 if(paramnotused(i))
521 continue;
522 break;
523 }
524 numparams++;
525 }
526
527 if (fractype != FORMULA && fractype != FFORMULA)
528 lastparm = numparams;
529
530 choose_vars_restart:
531
532 k = -1;
533 for (num = firstparm; num < lastparm; num++) {
534 if(fractype == FORMULA || fractype == FFORMULA)
535 if(paramnotused(num))
536 continue;
537 choices[++k]=gene[num].name;
538 uvalues[k].type = 'l';
539 uvalues[k].uval.ch.vlen = 7;
540 uvalues[k].uval.ch.llen = 7;
541 uvalues[k].uval.ch.list = evolvmodes;
542 uvalues[k].uval.ch.val = gene[num].mutate;
543 }
544
545 LOADCHOICES("");
546 uvalues[k].type = '*';
547 LOADCHOICES("Press F2 to set all to off");
548 uvalues[k].type ='*';
549 LOADCHOICES("Press F3 to set all on");
550 uvalues[k].type = '*';
551 LOADCHOICES("Press F4 to randomize all");
552 uvalues[k].type = '*';
553 LOADCHOICES("Press F6 for second page"); /* F5 gets eaten */
554 uvalues[k].type = '*';
555
556 i = fullscreen_prompt(hdg,k+1,choices,uvalues,92,NULL);
557
558 switch(i) {
559 case F2: /* set all off */
560 for (num = 0; num < MAXPARAMS; num++)
561 gene[num].mutate = 0;
562 goto choose_vars_restart;
563 case F3: /* set all on..alternate x and y for field map */
564 for (num = 0; num < MAXPARAMS; num ++ )
565 gene[num].mutate = (char)((num % 2) + 1);
566 goto choose_vars_restart;
567 case F4: /* Randomize all */
568 for (num =0; num < MAXPARAMS; num ++ )
569 gene[num].mutate = (char)(rand() % 6);
570 goto choose_vars_restart;
571 case F6: /* go to second screen, put array away first */
572 MoveToMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
573 chngd = get_the_rest();
574 MoveFromMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
575 goto choose_vars_restart;
576 case -1:
577 return(chngd);
578 default:
579 break;
580 }
581
582 /* read out values */
583 k = -1;
584 for (num = firstparm; num < lastparm; num++) {
585 if(fractype == FORMULA || fractype == FFORMULA)
586 if(paramnotused(num))
587 continue;
588 gene[num].mutate = (char)(uvalues[++k].uval.ch.val);
589 }
590
591 MoveToMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
592 return(1); /* if you were here, you want to regenerate */
593 }
594
595 void set_mutation_level(int strength)
596 {
597 /* scan through the gene array turning on random variation for all parms that */
598 /* are suitable for this level of mutation */
599 int i;
600 GENEBASE gene[NUMGENES];
601 /* get the gene array from far memory */
602 MoveFromMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
603
604 for (i=0;i<NUMGENES;i++) {
605 if(gene[i].level <= strength)
606 gene[i].mutate = 5; /* 5 = random mutation mode */
607 else
608 gene[i].mutate = 0;
609 }
610 /* now put the gene array back in far memory */
611 MoveToMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
612 return;
613 }
614
615 int get_evolve_Parms(void)
616 {
617 static FCODE o_hdg[]={"Evolution Mode Options"};
618 char hdg[sizeof(o_hdg)];
619 char far *choices[20];
620 char far *ptr;
621 int oldhelpmode;
622 struct fullscreenvalues uvalues[20];
623 int i,j, k, tmp;
624 int old_evolving,old_gridsz;
625 int old_variations = 0;
626 double old_paramrangex,old_paramrangey,old_opx,old_opy,old_fiddlefactor;
627
628 /* fill up the previous values arrays */
629 old_evolving = evolving;
630 old_gridsz = gridsz;
631 old_paramrangex = paramrangex;
632 old_paramrangey = paramrangey;
633 old_opx = opx;
634 old_opy = opy;
635 old_fiddlefactor = fiddlefactor;
636
637 get_evol_restart:
638
639 far_strcpy(hdg,o_hdg);
640 ptr = (char far *)MK_FP(extraseg,0);
641 if ((evolving & RANDWALK)||(evolving & RANDPARAM)) {
642 /* adjust field param to make some sense when changing from random modes*/
643 /* maybe should adjust for aspect ratio here? */
644 paramrangex = paramrangey = fiddlefactor * 2;
645 opx = param[0] - fiddlefactor;
646 opy = param[1] - fiddlefactor;
647 /* set middle image to last selected and edges to +- fiddlefactor */
648 }
649
650 k = -1;
651
652 LOADCHOICES("Evolution mode? (no for full screen)");
653 uvalues[k].type = 'y';
654 uvalues[k].uval.ch.val = evolving&1;
655
656 LOADCHOICES("Image grid size (odd numbers only)");
657 uvalues[k].type = 'i';
658 uvalues[k].uval.ival = gridsz;
659
660 if (explore_check()) { /* test to see if any parms are set to linear */
661 /* variation 'explore mode' */
662 LOADCHOICES("Show parameter zoom box?")
663 uvalues[k].type = 'y';
664 uvalues[k].uval.ch.val = ((evolving & PARMBOX) / PARMBOX);
665
666 LOADCHOICES("x parameter range (across screen)");
667 uvalues[k].type = 'f';
668 uvalues[k].uval.dval = paramrangex;
669
670 LOADCHOICES("x parameter offset (left hand edge)");
671 uvalues[k].type = 'f';
672 uvalues[k].uval.dval = opx;
673
674 LOADCHOICES("y parameter range (up screen)");
675 uvalues[k].type = 'f';
676 uvalues[k].uval.dval = paramrangey;
677
678 LOADCHOICES("y parameter offset (lower edge)");
679 uvalues[k].type = 'f';
680 uvalues[k].uval.dval= opy;
681 }
682
683 LOADCHOICES("Max random mutation");
684 uvalues[k].type = 'f';
685 uvalues[k].uval.dval = fiddlefactor;
686
687 LOADCHOICES("Mutation reduction factor (between generations)");
688 uvalues[k].type = 'f';
689 uvalues[k].uval.dval = fiddle_reduction;
690
691 LOADCHOICES("Grouting? ");
692 uvalues[k].type = 'y';
693 uvalues[k].uval.ch.val = !((evolving & NOGROUT) / NOGROUT);
694
695 LOADCHOICES("");
696 uvalues[k].type = '*';
697
698 LOADCHOICES("Press F4 to reset view parameters to defaults.");
699 uvalues[k].type = '*';
700
701 LOADCHOICES("Press F2 to halve mutation levels");
702 uvalues[k].type = '*';
703
704 LOADCHOICES("Press F3 to double mutation levels" );
705 uvalues[k].type ='*';
706
707 LOADCHOICES("Press F6 to control which parameters are varied");
708 uvalues[k].type = '*';
709 oldhelpmode = helpmode; /* this prevents HELP from activating */
710 helpmode = HELPEVOL;
711 i = fullscreen_prompt(hdg,k+1,choices,uvalues,255,NULL);
712 helpmode = oldhelpmode; /* re-enable HELP */
713 if (i < 0) {
714 /* in case this point has been reached after calling sub menu with F6 */
715 evolving = old_evolving;
716 gridsz = old_gridsz;
717 paramrangex = old_paramrangex;
718 paramrangey = old_paramrangey;
719 opx = old_opx;
720 opy = old_opy;
721 fiddlefactor = old_fiddlefactor;
722
723 return(-1);
724 }
725
726 if (i == F4) {
727 set_current_params();
728 fiddlefactor = 1;
729 fiddle_reduction = 1.0;
730 goto get_evol_restart;
731 }
732 if (i==F2 ) {
733 paramrangex = paramrangex / 2;
734 opx = newopx = opx + paramrangex / 2;
735 paramrangey = paramrangey / 2;
736 opy = newopy = opy + paramrangey / 2;
737 fiddlefactor = fiddlefactor / 2;
738 goto get_evol_restart;
739 }
740 if (i==F3 ) {
741 double centerx, centery;
742 centerx = opx + paramrangex / 2;
743 paramrangex = paramrangex * 2;
744 opx = newopx = centerx - paramrangex / 2;
745 centery = opy + paramrangey / 2;
746 paramrangey = paramrangey * 2;
747 opy = newopy = centery - paramrangey / 2;
748 fiddlefactor = fiddlefactor * 2;
749 goto get_evol_restart;
750 }
751
752 j = i;
753
754 /* now check out the results (*hopefully* in the same order <grin>) */
755
756 k = -1;
757
758 viewwindow = evolving = uvalues[++k].uval.ch.val;
759
760 if (!evolving && i != F6) /* don't need any of the other parameters JCO 12JUL2002 */
761 return(1); /* the following code can set evolving even if it's off */
762
763 gridsz = uvalues[++k].uval.ival;
764 tmp = sxdots / (MINPIXELS<<1);
765 /* (sxdots / 20), max # of subimages @ 20 pixels per subimage */
766 /* MAXGRIDSZ == 1024 / 20 == 51 */
767 if (gridsz > MAXGRIDSZ)
768 gridsz = MAXGRIDSZ;
769 if (gridsz > tmp)
770 gridsz = tmp;
771 if (gridsz < 3)
772 gridsz = 3;
773 gridsz |= 1; /* make sure gridsz is odd */
774 if (explore_check()) {
775 tmp = (PARMBOX * uvalues[++k].uval.ch.val);
776 if (evolving)
777 evolving += tmp;
778 paramrangex = uvalues[++k].uval.dval;
779 newopx = opx = uvalues[++k].uval.dval;
780 paramrangey = uvalues[++k].uval.dval;
781 newopy = opy = uvalues[++k].uval.dval;
782 }
783
784 fiddlefactor = uvalues[++k].uval.dval;
785
786 fiddle_reduction = uvalues[++k].uval.dval;
787
788 if (!(uvalues[++k].uval.ch.val)) evolving = evolving + NOGROUT;
789
790 viewxdots = (sxdots / gridsz)-2;
791 viewydots = (sydots / gridsz)-2;
792 if (!viewwindow) viewxdots=viewydots=0;
793
794 i = 0;
795
796 if ( evolving != old_evolving
797 || (gridsz != old_gridsz) ||(paramrangex!= old_paramrangex)
798 || (opx != old_opx ) || (paramrangey != old_paramrangey)
799 || (opy != old_opy) || (fiddlefactor != old_fiddlefactor)
800 || (old_variations > 0) )
801 i = 1;
802
803 if (evolving && !old_evolving)
804 param_history(0); /* save old history */
805
806 if (!evolving && (evolving == old_evolving)) i = 0;
807
808 if (j==F6) {
809 old_variations = get_variations();
810 set_current_params();
811 if (old_variations > 0)
812 {
813 viewwindow = 1;
814 evolving |= 1; /* leave other settings alone */
815 }
816 fiddlefactor = 1;
817 fiddle_reduction = 1.0;
818 goto get_evol_restart;
819 }
820 return(i);
821 }
822
823 void SetupParamBox(void)
824 {
825 int vidsize;
826 prmboxcount = 0;
827 parmzoom=((double)gridsz-1.0)/2.0;
828 /* need to allocate 2 int arrays for boxx and boxy plus 1 byte array for values */
829 vidsize = (xdots+ydots) * 4 * sizeof(int) ;
830 vidsize = vidsize + xdots + ydots + 2 ;
831 if (prmboxhandle == 0)
832 prmboxhandle = MemoryAlloc((U16)(vidsize),1L,FARMEM);
833 if (prmboxhandle == 0 ) {
834 static FCODE msg[] = {"Sorry...can't allocate mem for parmbox"};
835 texttempmsg(msg);
836 evolving=0;
837 }
838 prmboxcount=0;
839
840 /* vidsize = (vidsize / gridsz)+3 ; */ /* allocate less mem for smaller box */
841 /* taken out above as *all* pixels get plotted in small boxes */
842 if (imgboxhandle == 0)
843 imgboxhandle = MemoryAlloc((U16)(vidsize),1L,FARMEM);
844 if (!imgboxhandle) {
845 static FCODE msg[] = {"Sorry...can't allocate mem for imagebox"};
846 texttempmsg(msg);
847 }
848 }
849
850 void ReleaseParamBox(void)
851 {
852 MemoryRelease(prmboxhandle);
853 MemoryRelease(imgboxhandle);
854 prmboxhandle = 0;
855 imgboxhandle = 0;
856 }
857
858 void set_current_params(void)
859 {
860 paramrangex = curfractalspecific->xmax - curfractalspecific->xmin;
861 opx = newopx = - (paramrangex / 2);
862 paramrangey = curfractalspecific->ymax - curfractalspecific->ymin;
863 opy = newopy = - (paramrangey / 2);
864 return;
865 }
866
867 void fiddleparms(GENEBASE gene[], int ecount)
868 {
869 /* call with px,py ... parameter set co-ords*/
870 /* set random seed then call rnd enough times to get to px,py */
871 /* 5/2/96 adding in indirection */
872 /* 26/2/96 adding in multiple methods and field map */
873 /* 29/4/96 going for proper handling of the whole gene array */
874 /* bung in a pile of switches to allow for expansion to any
875 future variable types */
876 /* 11/6/96 scrapped most of switches above and used function pointers
877 instead */
878 /* 4/1/97 picking it up again after the last step broke it all horribly! */
879
880 int i;
881
882 /* when writing routines to vary param types make sure that rand() gets called
883 the same number of times whether gene[].mutate is set or not to allow
884 user to change it between generations without screwing up the duplicability
885 of the sequence and starting from the wrong point */
886
887 /* this function has got simpler and simpler throughout the construction of the
888 evolver feature and now consists of just these few lines to loop through all
889 the variables referenced in the gene array and call the functions required
890 to vary them, aren't pointers marvellous! */
891
892 if ((px == gridsz / 2) && (py == gridsz / 2)) /* return if middle image */
893 return;
894
895 set_random(ecount); /* generate the right number of pseudo randoms */
896
897 for (i=0;i<NUMGENES;i++)
898 (*(gene[i].varyfunc))(gene,rand(),i);
899
900 }
901
902 static void set_random(int ecount)
903 { /* This must be called with ecount set correctly for the spiral map. */
904 /* Call this routine to set the random # to the proper value */
905 /* if it may have changed, before fiddleparms() is called. */
906 /* Now called by fiddleparms(). */
907 int index,i;
908
909 srand(this_gen_rseed);
910 for (index=0;index < ecount;index++)
911 for (i=0;i<NUMGENES;i++)
912 rand();
913 }
914
915 int explore_check(void)
916 {
917 /* checks through gene array to see if any of the parameters are set to */
918 /* one of the non random variation modes. Used to see if parmzoom box is */
919 /* needed */
920 int nonrandom = FALSE;
921 int i;
922 GENEBASE gene[NUMGENES];
923 MoveFromMemory((BYTE *)&gene, (U16)sizeof(gene), 1L, 0L, gene_handle);
924 for (i=0;i<NUMGENES && !(nonrandom);i++)
925 if ((gene[i].mutate > 0) && (gene[i].mutate < 5)) nonrandom = TRUE;
926 return(nonrandom);
927 }
928
929 void drawparmbox(int mode)
930 {
931 /* draws parameter zoom box in evolver mode */
932 /* clears boxes off screen if mode=1, otherwise, redraws boxes */
933 struct coords tl,tr,bl,br;
934 int grout;
935 if (!(evolving & PARMBOX)) return; /* don't draw if not asked to! */
936 grout = !((evolving & NOGROUT)/NOGROUT) ;
937 imgboxcount = boxcount;
938 if (boxcount) {
939 /* stash normal zoombox pixels */
940 MoveToMemory((BYTE *)boxx,(U16)(boxcount*2),1L,0L,imgboxhandle);
941 MoveToMemory((BYTE *)boxy,(U16)(boxcount*2),1L,1L,imgboxhandle);
942 MoveToMemory((BYTE *)boxvalues,(U16)boxcount,1L,4L,imgboxhandle);
943 clearbox(); /* to avoid probs when one box overlaps the other */
944 }
945 if (prmboxcount!=0) { /* clear last parmbox */
946 boxcount=prmboxcount;
947 MoveFromMemory((BYTE *)boxx,(U16)(boxcount*2),1L,0L,prmboxhandle);
948 MoveFromMemory((BYTE *)boxy,(U16)(boxcount*2),1L,1L,prmboxhandle);
949 MoveFromMemory((BYTE *)boxvalues,(U16)boxcount,1L,4L,prmboxhandle);
950 clearbox();
951 }
952
953 if (mode == 1) {
954 boxcount = imgboxcount;
955 prmboxcount = 0;
956 return;
957 }
958
959 boxcount =0;
960 /*draw larger box to show parm zooming range */
961 tl.x = bl.x = ((px -(int)parmzoom) * (int)(dxsize+1+grout))-sxoffs-1;
962 tl.y = tr.y = ((py -(int)parmzoom) * (int)(dysize+1+grout))-syoffs-1;
963 br.x = tr.x = ((px +1+(int)parmzoom) * (int)(dxsize+1+grout))-sxoffs;
964 br.y = bl.y = ((py +1+(int)parmzoom) * (int)(dysize+1+grout))-syoffs;
965 #ifndef XFRACT
966 addbox(br);addbox(tr);addbox(bl);addbox(tl);
967 drawlines(tl,tr,bl.x-tl.x,bl.y-tl.y);
968 drawlines(tl,bl,tr.x-tl.x,tr.y-tl.y);
979 #endif
980 if(boxcount) {
981 dispbox();
982 /* stash pixel values for later */
983 MoveToMemory((BYTE *)boxx,(U16)(boxcount*2),1L,0L,prmboxhandle);
984 MoveToMemory((BYTE *)boxy,(U16)(boxcount*2),1L,1L,prmboxhandle);
985 MoveToMemory((BYTE *)boxvalues,(U16)boxcount,1L,4L,prmboxhandle);
986 }
987 prmboxcount = boxcount;
988 boxcount = imgboxcount;
989 if(imgboxcount) {
990 /* and move back old values so that everything can proceed as normal */
991 MoveFromMemory((BYTE *)boxx,(U16)(boxcount*2),1L,0L,imgboxhandle);
992 MoveFromMemory((BYTE *)boxy,(U16)(boxcount*2),1L,1L,imgboxhandle);
993 MoveFromMemory((BYTE *)boxvalues,(U16)boxcount,1L,4L,imgboxhandle);
994 dispbox();
995 }
996 return;
997 }
998
999 void set_evolve_ranges(void)
1000 {
1001 int lclpy = gridsz - py - 1;
1002 /* set up ranges and offsets for parameter explorer/evolver */
1003 paramrangex=dpx*(parmzoom*2.0);
1004 paramrangey=dpy*(parmzoom*2.0);
1005 newopx=opx+(((double)px-parmzoom)*dpx);
1006 newopy=opy+(((double)lclpy-parmzoom)*dpy);
1007
1008 newodpx=(char)(odpx+(px-gridsz/2));
1009 newodpy=(char)(odpy+(lclpy-gridsz/2));
1010 return;
1011 }
1012
1013 void spiralmap(int count)
1014 {
1015 /* maps out a clockwise spiral for a prettier and possibly */
1016 /* more intuitively useful order of drawing the sub images. */
1017 /* All the malarky with count is to allow resuming */
1018
1019 int i,mid,offset;
1020 i = 0;
1021 mid = gridsz / 2;
1022 if (count == 0) { /* start in the middle */
1023 px = py = mid;
1024 return;
1025 }
1026 for(offset = 1; offset <= mid; offset ++) {
1027 /* first do the top row */
1028 py = (mid - offset);
1029 for(px = (mid - offset)+1; px <mid+offset; px++) {
1030 i++;
1031 if (i==count) return;
1032 }
1033 /* then do the right hand column */
1034 for (; py < mid + offset; py++) {
1035 i++;
1036 if (i == count ) return;
1037 }
1038 /* then reverse along the bottom row */
1039 for (;px > mid - offset;px--) {
1040 i++;
1041 if (i == count) return;
1042 }
1043 /* then up the left to finish */
1044 for (; py >= mid - offset; py-- ) {
1045 i++;
1046 if (i== count ) return;
1047 }
1048 }
1049 }
1050
1051 int unspiralmap(void)
1052 {
1053 /* unmaps the clockwise spiral */
1054 /* All this malarky is to allow selecting different subimages */
1055 /* Returns the count from the center subimage to the current px & py */
1056 int mid;
1057 static int oldgridsz = 0;
1058
1059 mid = gridsz / 2;
1060 if ((px == mid && py == mid) || (oldgridsz != gridsz)) {
1061 int i, gridsqr;
1062 /* set up array and return */
1063 gridsqr = gridsz * gridsz;
1064 ecountbox[px][py] = 0; /* we know the first one, do the rest */
1065 for (i = 1; i < gridsqr; i++) {
1066 spiralmap(i);
1067 ecountbox[px][py] = i;
1068 }
1069 oldgridsz = gridsz;
1070 px = py = mid;
1071 return(0);
1072 }
1073 return(ecountbox[px][py]);
1074 }
1075
1076 /* points to ponder.....
1077 watch out for near mem..... (TW) It's better now.
1078 try and keep gene array in overlay? (TW) No, but try dynamic alloc.
1079 how to preserve 'what to mutate ' choices through overlay swaps in
1080 prompts... (TW) Needs checking, seems OK. LOADCHOICES copies, so is
1081 safe.
1082 */
1083
1084