File: common\fracsubr.c

    1 /*
    2 FRACSUBR.C contains subroutines which belong primarily to CALCFRAC.C and
    3 FRACTALS.C, i.e. which are non-fractal-specific fractal engine subroutines.
    4 */
    5 
    6 #ifndef USE_VARARGS
    7 #include <stdarg.h>
8 #else 9 #include <varargs.h>
10 #endif 11 12 #ifndef XFRACT 13 #include <sys/timeb.h> 14 #endif 15 #include <sys/types.h> 16 #include <time.h> 17 /* see Fractint.c for a description of the "include" hierarchy */ 18 #include "port.h" 19 #include "prototyp.h" 20 #include "fractype.h" 21 22 23 /* routines in this module */ 24 25 static long _fastcall fudgetolong(double d); 26 static double _fastcall fudgetodouble(long l); 27 static void _fastcall adjust_to_limits(double); 28 static void _fastcall smallest_add(double *); 29 static int _fastcall ratio_bad(double,double); 30 static void _fastcall plotdorbit(double,double,int); 31 static int _fastcall combine_worklist(void); 32 33 static void _fastcall adjust_to_limitsbf(double); 34 static void _fastcall smallest_add_bf(bf_t); 35 int resume_len; /* length of resume info */ 36 static int resume_offset; /* offset in resume info gets */ 37 int taborhelp; /* kludge for sound and tab or help key press */ 38 39 #define FUDGEFACTOR 29 /* fudge all values up by 2**this */ 40 #define FUDGEFACTOR2 24 /* (or maybe this) */ 41 42 void set_grid_pointers() 43 { 44 dx0 = MK_FP(extraseg,0); 45 dy1 = (dx1 = (dy0 = dx0 + xdots) + ydots) + ydots; 46 lx0 = (long far *) dx0; 47 ly1 = (lx1 = (ly0 = lx0 + xdots) + ydots) + ydots; 48 set_pixel_calc_functions(); 49 } 50 51 void fill_dx_array(void) 52 { 53 int i; 54 if(use_grid) 55 { 56 dx0[0] = xxmin; /* fill up the x, y grids */ 57 dy0[0] = yymax; 58 dx1[0] = dy1[0] = 0; 59 for (i = 1; i < xdots; i++ ) { 60 dx0[i] = (double)(dx0[0] + i*delxx); 61 dy1[i] = (double)(dy1[0] - i*delyy2); 62 } 63 for (i = 1; i < ydots; i++ ) { 64 dy0[i] = (double)(dy0[0] - i*delyy); 65 dx1[i] = (double)(dx1[0] + i*delxx2); 66 } 67 } 68 } 69 void fill_lx_array(void) 70 { 71 int i; 72 /* note that lx1 & ly1 values can overflow into sign bit; since */ 73 /* they're used only to add to lx0/ly0, 2s comp straightens it out */ 74 if(use_grid) 75 { 76 lx0[0] = xmin; /* fill up the x, y grids */ 77 ly0[0] = ymax; 78 lx1[0] = ly1[0] = 0; 79 for (i = 1; i < xdots; i++ ) { 80 lx0[i] = lx0[i-1] + delx; 81 ly1[i] = ly1[i-1] - dely2; 82 } 83 for (i = 1; i < ydots; i++ ) { 84 ly0[i] = ly0[i-1] - dely; 85 lx1[i] = lx1[i-1] + delx2; 86 } 87 } 88 } 89 90 void fractal_floattobf(void) 91 { 92 int i; 93 init_bf_dec(getprecdbl(CURRENTREZ)); 94 floattobf(bfxmin,xxmin); 95 floattobf(bfxmax,xxmax); 96 floattobf(bfymin,yymin); 97 floattobf(bfymax,yymax); 98 floattobf(bfx3rd,xx3rd); 99 floattobf(bfy3rd,yy3rd); 100 101 for (i = 0; i < MAXPARAMS; i++) 102 if(typehasparm(fractype,i,NULL)) 103 floattobf(bfparms[i],param[i]); 104 calc_status = 0; 105 } 106 107 108 #ifdef _MSC_VER 109 #if _MSC_VER == 800 110 /* MSC8 doesn't correctly calculate the address of certain arrays here */ 111 #pragma optimize( "", off ) 112 #endif 113 #endif 114 115 int use_grid; 116 117 void calcfracinit(void) /* initialize a *pile* of stuff for fractal calculation */ 118 { 119 int tries = 0; 120 int i, gotprec; 121 long xytemp; 122 double ftemp; 123 coloriter=oldcoloriter = 0L; 124 for(i=0;i<10;i++) 125 rhombus_stack[i] = 0; 126 127 /* set up grid array compactly leaving space at end */ 128 /* space req for grid is 2(xdots+ydots)*sizeof(long or double) */ 129 /* space available in extraseg is 65536 Bytes */ 130 xytemp = xdots + ydots; 131 if( ((usr_floatflag == 0) && (xytemp * sizeof(long) > 32768)) || 132 ((usr_floatflag == 1) && (xytemp * sizeof(double) > 32768)) || 133 debugflag == 3800) 134 { 135 use_grid=0; 136 floatflag = usr_floatflag = 1; 137 } 138 else 139 use_grid=1; 140 141 set_grid_pointers(); 142 143 if(!(curfractalspecific->flags & BF_MATH)) 144 { 145 int tofloat; 146 if((tofloat=curfractalspecific->tofloat) == NOFRACTAL) 147 bf_math = 0; 148 else if(!(fractalspecific[tofloat].flags & BF_MATH)) 149 bf_math = 0; 150 else if(bf_math) 151 { 152 curfractalspecific = &fractalspecific[tofloat]; 153 fractype = tofloat; 154 } 155 } 156 157 /* switch back to double when zooming out if using arbitrary precision */ 158 if(bf_math) 159 { 160 gotprec=getprecbf(CURRENTREZ); 161 if((gotprec <= DBL_DIG+1 && debugflag != 3200) || math_tol[1] >= 1.0) 162 { 163 bfcornerstofloat(); 164 bf_math = 0; 165 } 166 else 167 init_bf_dec(gotprec); 168 } 169 else if((fractype==MANDEL || fractype==MANDELFP) && debugflag==3200) 170 { 171 fractype=MANDELFP; 172 curfractalspecific = &fractalspecific[MANDELFP]; 173 fractal_floattobf(); 174 usr_floatflag = 1; 175 } 176 else if((fractype==JULIA || fractype==JULIAFP) && debugflag==3200) 177 { 178 fractype=JULIAFP; 179 curfractalspecific = &fractalspecific[JULIAFP]; 180 fractal_floattobf(); 181 usr_floatflag = 1; 182 } 183 else if((fractype==LMANDELZPOWER || fractype==FPMANDELZPOWER) && debugflag==3200) 184 { 185 fractype=FPMANDELZPOWER; 186 curfractalspecific = &fractalspecific[FPMANDELZPOWER]; 187 fractal_floattobf(); 188 usr_floatflag = 1; 189 } 190 else if((fractype==LJULIAZPOWER || fractype==FPJULIAZPOWER) && debugflag==3200) 191 { 192 fractype=FPJULIAZPOWER; 193 curfractalspecific = &fractalspecific[FPJULIAZPOWER]; 194 fractal_floattobf(); 195 usr_floatflag = 1; 196 } 197 else 198 free_bf_vars(); 199 if(bf_math) 200 floatflag=1; 201 else 202 floatflag = usr_floatflag; 203 if (calc_status == 2) { /* on resume, ensure floatflag correct */ 204 if (curfractalspecific->isinteger) 205 floatflag = 0; 206 else 207 floatflag = 1; 208 } 209 /* if floating pt only, set floatflag for TAB screen */ 210 if (!curfractalspecific->isinteger && curfractalspecific->tofloat == NOFRACTAL) 211 floatflag = 1; 212 if (usr_stdcalcmode == 's') { 213 if (fractype == MANDEL || fractype == MANDELFP) 214 floatflag = 1; 215 else 216 usr_stdcalcmode = '1'; 217 } 218 219 init_restart: 220 221 /* the following variables may be forced to a different setting due to 222 calc routine constraints; usr_xxx is what the user last said is wanted, 223 xxx is what we actually do in the current situation */ 224 stdcalcmode = usr_stdcalcmode; 225 periodicitycheck = usr_periodicitycheck; 226 distest = usr_distest; 227 biomorph = usr_biomorph; 228 229 potflag = 0; 230 if (potparam[0] != 0.0 231 && colors >= 64 232 && (curfractalspecific->calctype == StandardFractal 233 || curfractalspecific->calctype == calcmand 234 || curfractalspecific->calctype == calcmandfp)) { 235 potflag = 1; 236 distest = usr_distest = 0; /* can't do distest too */ 237 } 238 239 if (distest) 240 floatflag = 1; /* force floating point for dist est */ 241 242 if (floatflag) { /* ensure type matches floatflag */ 243 if (curfractalspecific->isinteger != 0 244 && curfractalspecific->tofloat != NOFRACTAL) 245 fractype = curfractalspecific->tofloat; 246 } 247 else { 248 if (curfractalspecific->isinteger == 0 249 && curfractalspecific->tofloat != NOFRACTAL) 250 fractype = curfractalspecific->tofloat; 251 } 252 /* match Julibrot with integer mode of orbit */ 253 if(fractype == JULIBROTFP && fractalspecific[neworbittype].isinteger) 254 { 255 int i; 256 if((i=fractalspecific[neworbittype].tofloat) != NOFRACTAL) 257 neworbittype = i; 258 else 259 fractype = JULIBROT; 260 } 261 else if(fractype == JULIBROT && fractalspecific[neworbittype].isinteger==0) 262 { 263 int i; 264 if((i=fractalspecific[neworbittype].tofloat) != NOFRACTAL) 265 neworbittype = i; 266 else 267 fractype = JULIBROTFP; 268 } 269 270 curfractalspecific = &fractalspecific[fractype]; 271 272 integerfractal = curfractalspecific->isinteger; 273 274 /* if (fractype == JULIBROT) 275 rqlim = 4; 276 else */ if (potflag && potparam[2] != 0.0) 277 rqlim = potparam[2]; 278 /* else if (decomp[0] > 0 && decomp[1] > 0) 279 rqlim = (double)decomp[1]; */ 280 else if (bailout) /* user input bailout */ 281 rqlim = bailout; 282 else if (biomorph != -1) /* biomorph benefits from larger bailout */ 283 rqlim = 100; 284 else 285 rqlim = curfractalspecific->orbit_bailout; 286 if (integerfractal) /* the bailout limit mustn't be too high here */ 287 if (rqlim > 127.0) rqlim = 127.0; 288 289 if ((curfractalspecific->flags&NOROTATE) != 0) { 290 /* ensure min<max and unrotated rectangle */ 291 if (xxmin > xxmax) { ftemp = xxmax; xxmax = xxmin; xxmin = ftemp; } 292 if (yymin > yymax) { ftemp = yymax; yymax = yymin; yymin = ftemp; } 293 xx3rd = xxmin; yy3rd = yymin; 294 } 295 296 /* set up bitshift for integer math */ 297 bitshift = FUDGEFACTOR2; /* by default, the smaller shift */ 298 if (integerfractal > 1) /* use specific override from table */ 299 bitshift = integerfractal; 300 if (integerfractal == 0) { /* float? */ 301 if ((i = curfractalspecific->tofloat) != NOFRACTAL) /* -> int? */ 302 { 303 if (fractalspecific[i].isinteger > 1) /* specific shift? */ 304 bitshift = fractalspecific[i].isinteger; 305 } 306 else 307 bitshift = 16; /* to allow larger corners */ 308 } 309 /* We want this code if we're using the assembler calcmand */ 310 if (fractype == MANDEL || fractype == JULIA) { /* adust shift bits if.. */ 311 if (potflag == 0 /* not using potential */ 312 && (param[0] > -2.0 && param[0] < 2.0) /* parameters not too large */ 313 && (param[1] > -2.0 && param[1] < 2.0) 314 && !invert /* and not inverting */ 315 && biomorph == -1 /* and not biomorphing */ 316 && rqlim <= 4.0 /* and bailout not too high */ 317 && (outside > -2 || outside < -6) /* and no funny outside stuff */ 318 && debugflag != 1234 /* and not debugging */ 319 && closeprox <= 2.0 /* and closeprox not too large */ 320 && bailoutest == Mod) /* and bailout test = mod */ 321 bitshift = FUDGEFACTOR; /* use the larger bitshift */ 322 } 323 324 fudge = 1L << bitshift; 325 326 l_at_rad = fudge/32768L; 327 f_at_rad = 1.0/32768L; 328 329 /* now setup arrays of real coordinates corresponding to each pixel */ 330 if(bf_math) 331 adjust_to_limitsbf(1.0); /* make sure all corners in valid range */ 332 else 333 { 334 adjust_to_limits(1.0); /* make sure all corners in valid range */ 335 delxx = (LDBL)(xxmax - xx3rd) / (LDBL)dxsize; /* calculate stepsizes */ 336 delyy = (LDBL)(yymax - yy3rd) / (LDBL)dysize; 337 delxx2 = (LDBL)(xx3rd - xxmin) / (LDBL)dysize; 338 delyy2 = (LDBL)(yy3rd - yymin) / (LDBL)dxsize; 339 fill_dx_array(); 340 } 341 342 if(fractype != CELLULAR && fractype != ANT) /* fudgetolong fails w >10 digits in double */ 343 { 344 creal = fudgetolong(param[0]); /* integer equivs for it all */ 345 cimag = fudgetolong(param[1]); 346 xmin = fudgetolong(xxmin); 347 xmax = fudgetolong(xxmax); 348 x3rd = fudgetolong(xx3rd); 349 ymin = fudgetolong(yymin); 350 ymax = fudgetolong(yymax); 351 y3rd = fudgetolong(yy3rd); 352 delx = fudgetolong((double)delxx); 353 dely = fudgetolong((double)delyy); 354 delx2 = fudgetolong((double)delxx2); 355 dely2 = fudgetolong((double)delyy2); 356 } 357 358 /* skip this if plasma to avoid 3d problems */ 359 /* skip if bf_math to avoid extraseg conflict with dx0 arrays */ 360 /* skip if ifs, ifs3d, or lsystem to avoid crash when mathtolerance */ 361 /* is set. These types don't auto switch between float and integer math */ 362 if (fractype != PLASMA && bf_math == 0 363 && fractype != IFS && fractype != IFS3D && fractype != LSYSTEM) 364 { 365 if (integerfractal && !invert && use_grid) 366 { 367 if ( (delx == 0 && delxx != 0.0) 368 || (delx2 == 0 && delxx2 != 0.0) 369 || (dely == 0 && delyy != 0.0) 370 || (dely2 == 0 && delyy2 != 0.0) ) 371 goto expand_retry; 372 373 fill_lx_array(); /* fill up the x,y grids */ 374 /* past max res? check corners within 10% of expected */ 375 if ( ratio_bad((double)lx0[xdots-1]-xmin,(double)xmax-x3rd) 376 || ratio_bad((double)ly0[ydots-1]-ymax,(double)y3rd-ymax) 377 || ratio_bad((double)lx1[(ydots>>1)-1],((double)x3rd-xmin)/2) 378 || ratio_bad((double)ly1[(xdots>>1)-1],((double)ymin-y3rd)/2) ) 379 { 380 expand_retry: 381 if (integerfractal /* integer fractal type? */ 382 && curfractalspecific->tofloat != NOFRACTAL) 383 floatflag = 1; /* switch to floating pt */ 384 else 385 adjust_to_limits(2.0); /* double the size */ 386 if (calc_status == 2) /* due to restore of an old file? */ 387 calc_status = 0; /* whatever, it isn't resumable */ 388 goto init_restart; 389 } /* end if ratio bad */ 390 391 /* re-set corners to match reality */ 392 xmax = lx0[xdots-1] + lx1[ydots-1]; 393 ymin = ly0[ydots-1] + ly1[xdots-1]; 394 x3rd = xmin + lx1[ydots-1]; 395 y3rd = ly0[ydots-1]; 396 xxmin = fudgetodouble(xmin); 397 xxmax = fudgetodouble(xmax); 398 xx3rd = fudgetodouble(x3rd); 399 yymin = fudgetodouble(ymin); 400 yymax = fudgetodouble(ymax); 401 yy3rd = fudgetodouble(y3rd); 402 } /* end if (integerfractal && !invert && use_grid) */ 403 else 404 { 405 double dx0,dy0,dx1,dy1; 406 /* set up dx0 and dy0 analogs of lx0 and ly0 */ 407 /* put fractal parameters in doubles */ 408 dx0 = xxmin; /* fill up the x, y grids */ 409 dy0 = yymax; 410 dx1 = dy1 = 0; 411 /* this way of defining the dx and dy arrays is not the most 412 accurate, but it is kept because it is used to determine 413 the limit of resolution */ 414 for (i = 1; i < xdots; i++ ) { 415 dx0 = (double)(dx0 + (double)delxx); 416 dy1 = (double)(dy1 - (double)delyy2); 417 } 418 for (i = 1; i < ydots; i++ ) { 419 dy0 = (double)(dy0 - (double)delyy); 420 dx1 = (double)(dx1 + (double)delxx2); 421 } 422 if(bf_math == 0) /* redundant test, leave for now */ 423 { 424 double testx_try, testx_exact; 425 double testy_try, testy_exact; 426 /* Following is the old logic for detecting failure of double 427 precision. It has two advantages: it is independent of the 428 representation of numbers, and it is sensitive to resolution 429 (allows depper zooms at lower resolution. However it fails 430 for rotations of exactly 90 degrees, so we added a safety net 431 by using the magnification. */ 432 if(++tries < 2) /* for safety */ 433 { 434 static FCODE err[] = {"precision-detection error"}; 435 if(tries > 1) stopmsg(0, err); 436 /* Previously there were four tests of distortions in the 437 zoom box used to detect precision limitations. In some 438 cases of rotated/skewed zoom boxs, this causes the algorithm 439 to bail out to arbitrary precision too soon. The logic 440 now only tests the larger of the two deltas in an attempt 441 to repair this bug. This should never make the transition 442 to arbitrary precision sooner, but always later.*/ 443 if(fabs(xxmax-xx3rd) > fabs(xx3rd-xxmin)) 444 { 445 testx_exact = xxmax-xx3rd; 446 testx_try = dx0-xxmin; 447 } 448 else 449 { 450 testx_exact = xx3rd-xxmin; 451 testx_try = dx1; 452 } 453 if(fabs(yy3rd-yymax) > fabs(yymin-yy3rd)) 454 { 455 testy_exact = yy3rd-yymax; 456 testy_try = dy0-yymax; 457 } 458 else 459 { 460 testy_exact = yymin-yy3rd; 461 testy_try = dy1; 462 } 463 if(ratio_bad(testx_try,testx_exact) || 464 ratio_bad(testy_try,testy_exact)) 465 { 466 if(curfractalspecific->flags & BF_MATH) 467 { 468 fractal_floattobf(); 469 goto init_restart; 470 } 471 goto expand_retry; 472 } /* end if ratio_bad etc. */ 473 } /* end if tries < 2 */ 474 } /* end if bf_math == 0 */ 475 476 /* if long double available, this is more accurate */ 477 fill_dx_array(); /* fill up the x, y grids */ 478 479 /* re-set corners to match reality */ 480 xxmax = (double)(xxmin + (xdots-1)*delxx + (ydots-1)*delxx2); 481 yymin = (double)(yymax - (ydots-1)*delyy - (xdots-1)*delyy2); 482 xx3rd = (double)(xxmin + (ydots-1)*delxx2); 483 yy3rd = (double)(yymax - (ydots-1)*delyy); 484 485 } /* end else */ 486 } /* end if not plasma */ 487 488 /* for periodicity close-enough, and for unity: */ 489 /* min(max(delx,delx2),max(dely,dely2) */ 490 ddelmin = fabs((double)delxx); 491 if (fabs((double)delxx2) > ddelmin) 492 ddelmin = fabs((double)delxx2); 493 if (fabs((double)delyy) > fabs((double)delyy2)) 494 { 495 if (fabs((double)delyy) < ddelmin) 496 ddelmin = fabs((double)delyy); 497 } 498 else if (fabs((double)delyy2) < ddelmin) 499 ddelmin = fabs((double)delyy2); 500 delmin = fudgetolong(ddelmin); 501 502 /* calculate factors which plot real values to screen co-ords */ 503 /* calcfrac.c plot_orbit routines have comments about this */ 504 ftemp = (double)((0.0-delyy2) * delxx2 * dxsize * dysize 505 - (xxmax-xx3rd) * (yy3rd-yymax)); 506 if(ftemp != 0) 507 { 508 plotmx1 = (double)(delxx2 * dxsize * dysize / ftemp); 509 plotmx2 = (yy3rd-yymax) * dxsize / ftemp; 510 plotmy1 = (double)((0.0-delyy2) * dxsize * dysize / ftemp); 511 plotmy2 = (xxmax-xx3rd) * dysize / ftemp; 512 } 513 if(bf_math == 0) 514 free_bf_vars(); 515 else 516 { 517 /* zap all of extraseg except high area to flush out bugs */ 518 /* in production version this code can be deleted */ 519 char far *extra; 520 extra = (char far *)MK_FP(extraseg,0); 521 far_memset(extra,0,(unsigned int)(0x10000l-(bflength+2)*22U)); 522 } 523 } 524 525 #ifdef _MSC_VER 526 #if _MSC_VER == 800 527 #pragma optimize( "", on ) /* restore optimization options */ 528 #endif 529 #endif 530 531 static long _fastcall fudgetolong(double d) 532 { 533 if ((d *= fudge) > 0) d += 0.5; 534 else d -= 0.5; 535 return (long)d; 536 } 537 538 static double _fastcall fudgetodouble(long l) 539 { 540 char buf[30]; 541 double d; 542 sprintf(buf,"%.9g",(double)l / fudge); 543 #ifndef XFRACT 544 sscanf(buf,"%lg",&d);
545 #else 546 sscanf(buf,"%lf",&d);
547 #endif 548 return d; 549 } 550 551 void adjust_cornerbf(void) 552 { 553 /* make edges very near vert/horiz exact, to ditch rounding errs and */ 554 /* to avoid problems when delta per axis makes too large a ratio */ 555 double ftemp; 556 double Xmagfactor, Rotation, Skew; 557 LDBL Magnification; 558 559 bf_t bftemp, bftemp2; 560 bf_t btmp1; 561 int saved; saved = save_stack(); 562 bftemp = alloc_stack(rbflength+2); 563 bftemp2 = alloc_stack(rbflength+2); 564 btmp1 = alloc_stack(rbflength+2); 565 566 /* While we're at it, let's adjust the Xmagfactor as well */ 567 /* use bftemp, bftemp2 as bfXctr, bfYctr */ 568 cvtcentermagbf(bftemp, bftemp2, &Magnification, &Xmagfactor, &Rotation, &Skew); 569 ftemp = fabs(Xmagfactor); 570 if (ftemp != 1 && ftemp >= (1-aspectdrift) && ftemp <= (1+aspectdrift)) 571 { 572 Xmagfactor = sign(Xmagfactor); 573 cvtcornersbf(bftemp, bftemp2, Magnification, Xmagfactor, Rotation, Skew); 574 } 575 576 /* ftemp=fabs(xx3rd-xxmin); */ 577 abs_a_bf(sub_bf(bftemp,bfx3rd,bfxmin)); 578 579 /* ftemp2=fabs(xxmax-xx3rd);*/ 580 abs_a_bf(sub_bf(bftemp2,bfxmax,bfx3rd)); 581 582 /* if( (ftemp=fabs(xx3rd-xxmin)) < (ftemp2=fabs(xxmax-xx3rd)) ) */ 583 if(cmp_bf(bftemp,bftemp2) < 0) 584 { 585 /* if (ftemp*10000 < ftemp2 && yy3rd != yymax) */ 586 if (cmp_bf(mult_bf_int(btmp1,bftemp,10000),bftemp2) < 0 587 && cmp_bf(bfy3rd,bfymax) != 0 ) 588 /* xx3rd = xxmin; */ 589 copy_bf(bfx3rd, bfxmin); 590 } 591 592 /* else if (ftemp2*10000 < ftemp && yy3rd != yymin) */ 593 if (cmp_bf(mult_bf_int(btmp1,bftemp2,10000),bftemp) < 0 594 && cmp_bf(bfy3rd,bfymin) != 0 ) 595 /* xx3rd = xxmax; */ 596 copy_bf(bfx3rd, bfxmax); 597 598 /* ftemp=fabs(yy3rd-yymin); */ 599 abs_a_bf(sub_bf(bftemp,bfy3rd,bfymin)); 600 601 /* ftemp2=fabs(yymax-yy3rd); */ 602 abs_a_bf(sub_bf(bftemp2,bfymax,bfy3rd)); 603 604 /* if( (ftemp=fabs(yy3rd-yymin)) < (ftemp2=fabs(yymax-yy3rd)) ) */ 605 if(cmp_bf(bftemp,bftemp2) < 0) 606 { 607 /* if (ftemp*10000 < ftemp2 && xx3rd != xxmax) */ 608 if (cmp_bf(mult_bf_int(btmp1,bftemp,10000),bftemp2) < 0 609 && cmp_bf(bfx3rd,bfxmax) != 0 ) 610 /* yy3rd = yymin; */ 611 copy_bf(bfy3rd, bfymin); 612 } 613 614 /* else if (ftemp2*10000 < ftemp && xx3rd != xxmin) */ 615 if (cmp_bf(mult_bf_int(btmp1,bftemp2,10000),bftemp) < 0 616 && cmp_bf(bfx3rd,bfxmin) != 0 ) 617 /* yy3rd = yymax; */ 618 copy_bf(bfy3rd, bfymax); 619 620 621 restore_stack(saved); 622 } 623 624 void adjust_corner(void) 625 { 626 /* make edges very near vert/horiz exact, to ditch rounding errs and */ 627 /* to avoid problems when delta per axis makes too large a ratio */ 628 double ftemp,ftemp2; 629 double Xctr, Yctr, Xmagfactor, Rotation, Skew; 630 LDBL Magnification; 631 632 if(!integerfractal) 633 { 634 /* While we're at it, let's adjust the Xmagfactor as well */ 635 cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew); 636 ftemp = fabs(Xmagfactor); 637 if (ftemp != 1 && ftemp >= (1-aspectdrift) && ftemp <= (1+aspectdrift)) 638 { 639 Xmagfactor = sign(Xmagfactor); 640 cvtcorners(Xctr, Yctr, Magnification, Xmagfactor, Rotation, Skew); 641 } 642 } 643 644 if( (ftemp=fabs(xx3rd-xxmin)) < (ftemp2=fabs(xxmax-xx3rd)) ) { 645 if (ftemp*10000 < ftemp2 && yy3rd != yymax) 646 xx3rd = xxmin; 647 } 648 649 if (ftemp2*10000 < ftemp && yy3rd != yymin) 650 xx3rd = xxmax; 651 652 if( (ftemp=fabs(yy3rd-yymin)) < (ftemp2=fabs(yymax-yy3rd)) ) { 653 if (ftemp*10000 < ftemp2 && xx3rd != xxmax) 654 yy3rd = yymin; 655 } 656 657 if (ftemp2*10000 < ftemp && xx3rd != xxmin) 658 yy3rd = yymax; 659 660 } 661 662 static void _fastcall adjust_to_limitsbf(double expand) 663 { 664 LDBL limit; 665 bf_t bcornerx[4],bcornery[4]; 666 bf_t blowx,bhighx,blowy,bhighy,blimit,bftemp; 667 bf_t bcenterx,bcentery,badjx,badjy,btmp1,btmp2; 668 bf_t bexpand; 669 int i; 670 int saved; saved = save_stack(); 671 bcornerx[0] = alloc_stack(rbflength+2); 672 bcornerx[1] = alloc_stack(rbflength+2); 673 bcornerx[2] = alloc_stack(rbflength+2); 674 bcornerx[3] = alloc_stack(rbflength+2); 675 bcornery[0] = alloc_stack(rbflength+2); 676 bcornery[1] = alloc_stack(rbflength+2); 677 bcornery[2] = alloc_stack(rbflength+2); 678 bcornery[3] = alloc_stack(rbflength+2); 679 blowx = alloc_stack(rbflength+2); 680 bhighx = alloc_stack(rbflength+2); 681 blowy = alloc_stack(rbflength+2); 682 bhighy = alloc_stack(rbflength+2); 683 blimit = alloc_stack(rbflength+2); 684 bftemp = alloc_stack(rbflength+2); 685 bcenterx = alloc_stack(rbflength+2); 686 bcentery = alloc_stack(rbflength+2); 687 badjx = alloc_stack(rbflength+2); 688 badjy = alloc_stack(rbflength+2); 689 btmp1 = alloc_stack(rbflength+2); 690 btmp2 = alloc_stack(rbflength+2); 691 bexpand = alloc_stack(rbflength+2); 692 693 limit = 32767.99; 694 695 /* if (bitshift >= 24) limit = 31.99; 696 if (bitshift >= 29) limit = 3.99; */ 697 floattobf(blimit,limit); 698 floattobf(bexpand,expand); 699 700 add_bf(bcenterx,bfxmin,bfxmax); 701 half_a_bf(bcenterx); 702 703 /* centery = (yymin+yymax)/2; */ 704 add_bf(bcentery,bfymin,bfymax); 705 half_a_bf(bcentery); 706 707 /* if (xxmin == centerx) { */ 708 if (cmp_bf(bfxmin,bcenterx)==0) { /* ohoh, infinitely thin, fix it */ 709 smallest_add_bf(bfxmax); 710 /* bfxmin -= bfxmax-centerx; */ 711 sub_a_bf(bfxmin,sub_bf(btmp1,bfxmax,bcenterx)); 712 } 713 714 /* if (bfymin == centery) */ 715 if (cmp_bf(bfymin,bcentery)==0) { 716 smallest_add_bf(bfymax); 717 /* bfymin -= bfymax-centery; */ 718 sub_a_bf(bfymin,sub_bf(btmp1,bfymax,bcentery)); 719 } 720 721 /* if (bfx3rd == centerx) */ 722 if (cmp_bf(bfx3rd,bcenterx)==0) 723 smallest_add_bf(bfx3rd); 724 725 /* if (bfy3rd == centery) */ 726 if (cmp_bf(bfy3rd,bcentery)==0) 727 smallest_add_bf(bfy3rd); 728 729 /* setup array for easier manipulation */ 730 /* cornerx[0] = xxmin; */ 731 copy_bf(bcornerx[0],bfxmin); 732 733 /* cornerx[1] = xxmax; */ 734 copy_bf(bcornerx[1],bfxmax); 735 736 /* cornerx[2] = xx3rd; */ 737 copy_bf(bcornerx[2],bfx3rd); 738 739 /* cornerx[3] = xxmin+(xxmax-xx3rd); */ 740 sub_bf(bcornerx[3],bfxmax,bfx3rd); 741 add_a_bf(bcornerx[3],bfxmin); 742 743 /* cornery[0] = yymax; */ 744 copy_bf(bcornery[0],bfymax); 745 746 /* cornery[1] = yymin; */ 747 copy_bf(bcornery[1],bfymin); 748 749 /* cornery[2] = yy3rd; */ 750 copy_bf(bcornery[2],bfy3rd); 751 752 /* cornery[3] = yymin+(yymax-yy3rd); */ 753 sub_bf(bcornery[3],bfymax,bfy3rd); 754 add_a_bf(bcornery[3],bfymin); 755 756 /* if caller wants image size adjusted, do that first */ 757 if (expand != 1.0) 758 { 759 for (i=0; i<4; ++i) { 760 /* cornerx[i] = centerx + (cornerx[i]-centerx)*expand; */ 761 sub_bf(btmp1,bcornerx[i],bcenterx); 762 mult_bf(bcornerx[i],btmp1,bexpand); 763 add_a_bf(bcornerx[i],bcenterx); 764 765 /* cornery[i] = centery + (cornery[i]-centery)*expand; */ 766 sub_bf(btmp1,bcornery[i],bcentery); 767 mult_bf(bcornery[i],btmp1,bexpand); 768 add_a_bf(bcornery[i],bcentery); 769 } 770 } 771 772 /* get min/max x/y values */ 773 /* lowx = highx = cornerx[0]; */ 774 copy_bf(blowx,bcornerx[0]); copy_bf(bhighx,bcornerx[0]); 775 776 /* lowy = highy = cornery[0]; */ 777 copy_bf(blowy,bcornery[0]); copy_bf(bhighy,bcornery[0]); 778 779 for (i=1; i<4; ++i) { 780 /* if (cornerx[i] < lowx) lowx = cornerx[i]; */ 781 if (cmp_bf(bcornerx[i],blowx) < 0) copy_bf(blowx,bcornerx[i]); 782 783 /* if (cornerx[i] > highx) highx = cornerx[i]; */ 784 if (cmp_bf(bcornerx[i],bhighx) > 0) copy_bf(bhighx,bcornerx[i]); 785 786 /* if (cornery[i] < lowy) lowy = cornery[i]; */ 787 if (cmp_bf(bcornery[i],blowy) < 0) copy_bf(blowy,bcornery[i]); 788 789 /* if (cornery[i] > highy) highy = cornery[i]; */ 790 if (cmp_bf(bcornery[i],bhighy) > 0) copy_bf(bhighy,bcornery[i]); 791 } 792 793 /* if image is too large, downsize it maintaining center */ 794 /* ftemp = highx-lowx; */ 795 sub_bf(bftemp,bhighx,blowx); 796 797 /* if (highy-lowy > ftemp) ftemp = highy-lowy; */ 798 if (cmp_bf(sub_bf(btmp1,bhighy,blowy),bftemp) > 0) copy_bf(bftemp,btmp1); 799 800 /* if image is too large, downsize it maintaining center */ 801 802 floattobf(btmp1,limit*2.0); 803 copy_bf(btmp2,bftemp); 804 div_bf(bftemp,btmp1,btmp2); 805 floattobf(btmp1,1.0); 806 if (cmp_bf(bftemp,btmp1) < 0) 807 for (i=0; i<4; ++i) { 808 /* cornerx[i] = centerx + (cornerx[i]-centerx)*ftemp; */ 809 sub_bf(btmp1,bcornerx[i],bcenterx); 810 mult_bf(bcornerx[i],btmp1,bftemp); 811 add_a_bf(bcornerx[i],bcenterx); 812 813 /* cornery[i] = centery + (cornery[i]-centery)*ftemp; */ 814 sub_bf(btmp1,bcornery[i],bcentery); 815 mult_bf(bcornery[i],btmp1,bftemp); 816 add_a_bf(bcornery[i],bcentery); 817 } 818 819 /* if any corner has x or y past limit, move the image */ 820 /* adjx = adjy = 0; */ 821 clear_bf(badjx); clear_bf(badjy); 822 823 for (i=0; i<4; ++i) { 824 /* if (cornerx[i] > limit && (ftemp = cornerx[i] - limit) > adjx) 825 adjx = ftemp; */ 826 if (cmp_bf(bcornerx[i],blimit) > 0 && 827 cmp_bf(sub_bf(bftemp,bcornerx[i],blimit),badjx) > 0) 828 copy_bf(badjx,bftemp); 829 830 /* if (cornerx[i] < 0.0-limit && (ftemp = cornerx[i] + limit) < adjx) 831 adjx = ftemp; */ 832 if (cmp_bf(bcornerx[i],neg_bf(btmp1,blimit)) < 0 && 833 cmp_bf(add_bf(bftemp,bcornerx[i],blimit),badjx) < 0) 834 copy_bf(badjx,bftemp); 835 836 /* if (cornery[i] > limit && (ftemp = cornery[i] - limit) > adjy) 837 adjy = ftemp; */ 838 if (cmp_bf(bcornery[i],blimit) > 0 && 839 cmp_bf(sub_bf(bftemp,bcornery[i],blimit),badjy) > 0) 840 copy_bf(badjy,bftemp); 841 842 /* if (cornery[i] < 0.0-limit && (ftemp = cornery[i] + limit) < adjy) 843 adjy = ftemp; */ 844 if (cmp_bf(bcornery[i],neg_bf(btmp1,blimit)) < 0 && 845 cmp_bf(add_bf(bftemp,bcornery[i],blimit),badjy) < 0) 846 copy_bf(badjy,bftemp); 847 } 848 849 /* if (calc_status == 2 && (adjx != 0 || adjy != 0) && (zwidth == 1.0)) 850 calc_status = 0; */ 851 if (calc_status == 2 && (is_bf_not_zero(badjx)|| is_bf_not_zero(badjy)) && (zwidth == 1.0)) 852 calc_status = 0; 853 854 /* xxmin = cornerx[0] - adjx; */ 855 sub_bf(bfxmin,bcornerx[0],badjx); 856 /* xxmax = cornerx[1] - adjx; */ 857 sub_bf(bfxmax,bcornerx[1],badjx); 858 /* xx3rd = cornerx[2] - adjx; */ 859 sub_bf(bfx3rd,bcornerx[2],badjx); 860 /* yymax = cornery[0] - adjy; */ 861 sub_bf(bfymax,bcornery[0],badjy); 862 /* yymin = cornery[1] - adjy; */ 863 sub_bf(bfymin,bcornery[1],badjy); 864 /* yy3rd = cornery[2] - adjy; */ 865 sub_bf(bfy3rd,bcornery[2],badjy); 866 867 adjust_cornerbf(); /* make 3rd corner exact if very near other co-ords */ 868 restore_stack(saved); 869 } 870 871 static void _fastcall adjust_to_limits(double expand) 872 { 873 double cornerx[4],cornery[4]; 874 double lowx,highx,lowy,highy,limit,ftemp; 875 double centerx,centery,adjx,adjy; 876 int i; 877 878 limit = 32767.99; 879 880 if (integerfractal) { 881 if (save_release > 1940) /* let user reproduce old GIF's and PAR's */ 882 limit = 1023.99; 883 if (bitshift >= 24) limit = 31.99; 884 if (bitshift >= 29) limit = 3.99; 885 } 886 887 centerx = (xxmin+xxmax)/2; 888 centery = (yymin+yymax)/2; 889 890 if (xxmin == centerx) { /* ohoh, infinitely thin, fix it */ 891 smallest_add(&xxmax); 892 xxmin -= xxmax-centerx; 893 } 894 895 if (yymin == centery) { 896 smallest_add(&yymax); 897 yymin -= yymax-centery; 898 } 899 900 if (xx3rd == centerx) 901 smallest_add(&xx3rd); 902 903 if (yy3rd == centery) 904 smallest_add(&yy3rd); 905 906 /* setup array for easier manipulation */ 907 cornerx[0] = xxmin; 908 cornerx[1] = xxmax; 909 cornerx[2] = xx3rd; 910 cornerx[3] = xxmin+(xxmax-xx3rd); 911 912 cornery[0] = yymax; 913 cornery[1] = yymin; 914 cornery[2] = yy3rd; 915 cornery[3] = yymin+(yymax-yy3rd); 916 917 /* if caller wants image size adjusted, do that first */ 918 if (expand != 1.0) 919 { 920 for (i=0; i<4; ++i) { 921 cornerx[i] = centerx + (cornerx[i]-centerx)*expand; 922 cornery[i] = centery + (cornery[i]-centery)*expand; 923 } 924 } 925 /* get min/max x/y values */ 926 lowx = highx = cornerx[0]; 927 lowy = highy = cornery[0]; 928 929 for (i=1; i<4; ++i) { 930 if (cornerx[i] < lowx) lowx = cornerx[i]; 931 if (cornerx[i] > highx) highx = cornerx[i]; 932 if (cornery[i] < lowy) lowy = cornery[i]; 933 if (cornery[i] > highy) highy = cornery[i]; 934 } 935 936 /* if image is too large, downsize it maintaining center */ 937 ftemp = highx-lowx; 938 939 if (highy-lowy > ftemp) ftemp = highy-lowy; 940 941 /* if image is too large, downsize it maintaining center */ 942 if ((ftemp = limit*2/ftemp) < 1.0) { 943 for (i=0; i<4; ++i) { 944 cornerx[i] = centerx + (cornerx[i]-centerx)*ftemp; 945 cornery[i] = centery + (cornery[i]-centery)*ftemp; 946 } 947 } 948 949 /* if any corner has x or y past limit, move the image */ 950 adjx = adjy = 0; 951 952 for (i=0; i<4; ++i) { 953 if (cornerx[i] > limit && (ftemp = cornerx[i] - limit) > adjx) 954 adjx = ftemp; 955 if (cornerx[i] < 0.0-limit && (ftemp = cornerx[i] + limit) < adjx) 956 adjx = ftemp; 957 if (cornery[i] > limit && (ftemp = cornery[i] - limit) > adjy) 958 adjy = ftemp; 959 if (cornery[i] < 0.0-limit && (ftemp = cornery[i] + limit) < adjy) 960 adjy = ftemp; 961 } 962 if (calc_status == 2 && (adjx != 0 || adjy != 0) && (zwidth == 1.0)) 963 calc_status = 0; 964 xxmin = cornerx[0] - adjx; 965 xxmax = cornerx[1] - adjx; 966 xx3rd = cornerx[2] - adjx; 967 yymax = cornery[0] - adjy; 968 yymin = cornery[1] - adjy; 969 yy3rd = cornery[2] - adjy; 970 971 adjust_corner(); /* make 3rd corner exact if very near other co-ords */ 972 } 973 974 static void _fastcall smallest_add(double *num) 975 { 976 *num += *num * 5.0e-16; 977 } 978 979 static void _fastcall smallest_add_bf(bf_t num) 980 { 981 bf_t btmp1; 982 int saved; saved = save_stack(); 983 btmp1 = alloc_stack(bflength+2); 984 mult_bf(btmp1,floattobf(btmp1, 5.0e-16),num); 985 add_a_bf(num,btmp1); 986 restore_stack(saved); 987 } 988 989 static int _fastcall ratio_bad(double actual, double desired) 990 { 991 double ftemp, tol; 992 if(integerfractal) 993 tol = math_tol[0]; 994 else 995 tol = math_tol[1]; 996 if(tol <= 0.0) 997 return(1); 998 else if(tol >= 1.0) 999 return(0); 1000 ftemp = 0; 1001 if (desired != 0 && debugflag != 3400) 1002 ftemp = actual / desired; 1003 if (desired != 0 && debugflag != 3400) 1004 if ((ftemp = actual / desired) < (1.0-tol) || ftemp > (1.0+tol)) 1005 return(1); 1006 return(0); 1007 } 1008 1009 1010 /* Save/resume stuff: 1011 1012 Engines which aren't resumable can simply ignore all this. 1013 1014 Before calling the (per_image,calctype) routines (engine), calcfract sets: 1015 "resuming" to 0 if new image, nonzero if resuming a partially done image 1016 "calc_status" to 1 1017 If an engine is interrupted and wants to be able to resume it must: 1018 store whatever status info it needs to be able to resume later 1019 set calc_status to 2 and return 1020 If subsequently called with resuming!=0, the engine must restore status 1021 info and continue from where it left off. 1022 1023 Since the info required for resume can get rather large for some types, 1024 it is not stored directly in save_info. Instead, memory is dynamically 1025 allocated as required, and stored in .fra files as a separate block. 1026 To save info for later resume, an engine routine can use: 1027 alloc_resume(maxsize,version) 1028 Maxsize must be >= max bytes subsequently saved + 2; over-allocation 1029 is harmless except for possibility of insufficient mem available; 1030 undersize is not checked and probably causes serious misbehaviour. 1031 Version is an arbitrary number so that subsequent revisions of the 1032 engine can be made backward compatible. 1033 Alloc_resume sets calc_status to 2 (resumable) if it succeeds; to 3 1034 if it cannot allocate memory (and issues warning to user). 1035 put_resume({bytes,&argument,} ... 0) 1036 Can be called as often as required to store the info. 1037 Arguments must not be far addresses. 1038 Is not protected against calls which use more space than allocated. 1039 To reload info when resuming, use: 1040 start_resume() 1041 initializes and returns version number 1042 get_resume({bytes,&argument,} ... 0) 1043 inverse of store_resume 1044 end_resume() 1045 optional, frees the memory area sooner than would happen otherwise 1046 1047 Example, save info: 1048 alloc_resume(sizeof(parmarray)+100,2); 1049 put_resume(sizeof(row),&row, sizeof(col),&col, 1050 sizeof(parmarray),parmarray, 0); 1051 restore info: 1052 vsn = start_resume(); 1053 get_resume(sizeof(row),&row, sizeof(col),&col, 0); 1054 if (vsn >= 2) 1055 get_resume(sizeof(parmarray),parmarray,0); 1056 end_resume(); 1057 1058 Engines which allocate a large far memory chunk of their own might 1059 directly set resume_info, resume_len, calc_status to avoid doubling 1060 transient memory needs by using these routines. 1061 1062 StandardFractal, calcmand, solidguess, and bound_trace_main are a related 1063 set of engines for escape-time fractals. They use a common worklist 1064 structure for save/resume. Fractals using these must specify calcmand 1065 or StandardFractal as the engine in fractalspecificinfo. 1066 Other engines don't get btm nor ssg, don't get off-axis symmetry nor 1067 panning (the worklist stuff), and are on their own for save/resume. 1068 1069 */ 1070 1071 #ifndef USE_VARARGS 1072 int put_resume(int len, ...)
1073 #else 1074 int put_resume(va_alist) 1075 va_dcl
1076 #endif 1077 { 1078 va_list arg_marker; /* variable arg list */ 1079 BYTE *source_ptr; 1080 #ifdef USE_VARARGS
1081 int len;
1082 #endif 1083 1084 if (resume_info == 0) 1085 return(-1); 1086 #ifndef USE_VARARGS 1087 va_start(arg_marker,len);
1088 #else 1089 va_start(arg_marker); 1090 len = va_arg(arg_marker,int);
1091 #endif 1092 while (len) 1093 { 1094 source_ptr = (BYTE *)va_arg(arg_marker,char *); 1095 /* far_memcpy(resume_info+resume_len,source_ptr,len); */ 1096 MoveToMemory(source_ptr,(U16)1,(long)len,resume_len,resume_info); 1097 resume_len += len; 1098 len = va_arg(arg_marker,int); 1099 } 1100 va_end(arg_marker); 1101 return(0); 1102 } 1103 1104 int alloc_resume(int alloclen, int version) 1105 { /* WARNING! if alloclen > 4096B, problems may occur with GIF save/restore */ 1106 if (resume_info != 0) /* free the prior area if there is one */ 1107 MemoryRelease(resume_info); 1108 if ((resume_info = MemoryAlloc((U16)sizeof(alloclen), (long)alloclen, FARMEM)) == 0) 1109 { 1110 static FCODE msg[] = {"\ 1111 Warning - insufficient free memory to save status.\n\ 1112 You will not be able to resume calculating this image."}; 1113 stopmsg(0,msg); 1114 calc_status = 3; 1115 return(-1); 1116 } 1117 resume_len = 0; 1118 put_resume(sizeof(version),&version,0); 1119 calc_status = 2; 1120 return(0); 1121 } 1122 1123 #ifndef USE_VARARGS 1124 int get_resume(int len, ...)
1125 #else 1126 int get_resume(va_alist) 1127 va_dcl
1128 #endif 1129 { 1130 va_list arg_marker; /* variable arg list */ 1131 BYTE *dest_ptr; 1132 #ifdef USE_VARARGS
1133 int len;
1134 #endif 1135 1136 if (resume_info == 0) 1137 return(-1); 1138 #ifndef USE_VARARGS 1139 va_start(arg_marker,len);
1140 #else 1141 va_start(arg_marker); 1142 len = va_arg(arg_marker,int);
1143 #endif 1144 while (len) 1145 { 1146 dest_ptr = (BYTE *)va_arg(arg_marker,char *); 1147 /* far_memcpy(dest_ptr,resume_info+resume_offset,len); */ 1148 MoveFromMemory(dest_ptr,(U16)1,(long)len,resume_offset,resume_info); 1149 resume_offset += len; 1150 len = va_arg(arg_marker,int); 1151 } 1152 va_end(arg_marker); 1153 return(0); 1154 } 1155 1156 int start_resume(void) 1157 { 1158 int version; 1159 if (resume_info == 0) 1160 return(-1); 1161 resume_offset = 0; 1162 get_resume(sizeof(version),&version,0); 1163 return(version); 1164 } 1165 1166 void end_resume(void) 1167 { 1168 if (resume_info != 0) /* free the prior area if there is one */ 1169 { 1170 MemoryRelease(resume_info); 1171 resume_info = 0; 1172 } 1173 } 1174 1175 1176 /* Showing orbit requires converting real co-ords to screen co-ords. 1177 Define: 1178 Xs == xxmax-xx3rd Ys == yy3rd-yymax 1179 W == xdots-1 D == ydots-1 1180 We know that: 1181 realx == lx0[col] + lx1[row] 1182 realy == ly0[row] + ly1[col] 1183 lx0[col] == (col/width) * Xs + xxmin 1184 lx1[row] == row * delxx 1185 ly0[row] == (row/D) * Ys + yymax 1186 ly1[col] == col * (0-delyy) 1187 so: 1188 realx == (col/W) * Xs + xxmin + row * delxx 1189 realy == (row/D) * Ys + yymax + col * (0-delyy) 1190 and therefore: 1191 row == (realx-xxmin - (col/W)*Xs) / Xv (1) 1192 col == (realy-yymax - (row/D)*Ys) / Yv (2) 1193 substitute (2) into (1) and solve for row: 1194 row == ((realx-xxmin)*(0-delyy2)*W*D - (realy-yymax)*Xs*D) 1195 / ((0-delyy2)*W*delxx2*D-Ys*Xs) 1196 */ 1197 1198 /* sleep N * a tenth of a millisecond */ 1199 1200 void sleepms_old(long ms) 1201 { 1202 static long scalems = 0L; 1203 int savehelpmode,savetabmode; 1204 struct timebx t1,t2; 1205 #define SLEEPINIT 250 /* milliseconds for calibration */ 1206 savetabmode = tabmode; 1207 savehelpmode = helpmode; 1208 tabmode = 0; 1209 helpmode = -1; 1210 if(scalems==0L) /* calibrate */ 1211 { 1212 /* selects a value of scalems that makes the units 1213 10000 per sec independent of CPU speed */ 1214 int i,elapsed; 1215 scalems = 1L; 1216 if(keypressed()) /* check at start, hope to get start of timeslice */ 1217 goto sleepexit; 1218 /* calibrate, assume slow computer first */ 1219 showtempmsg("Calibrating timer"); 1220 do 1221 { 1222 scalems *= 2; 1223 ftimex(&t2); 1224 do { /* wait for the start of a new tick */ 1225 ftimex(&t1); 1226 } 1227 while (t2.time == t1.time && t2.millitm == t1.millitm); 1228 sleepms_old(10L * SLEEPINIT); /* about 1/4 sec */ 1229 ftimex(&t2); 1230 if(keypressed()) { 1231 scalems = 0L; 1232 cleartempmsg(); 1233 goto sleepexit; 1234 } 1235 } 1236 while ((elapsed = (int)(t2.time-t1.time)*1000 + t2.millitm-t1.millitm) 1237 < SLEEPINIT); 1238 /* once more to see if faster (eg multi-tasking) */ 1239 do { /* wait for the start of a new tick */ 1240 ftimex(&t1); 1241 } 1242 while (t2.time == t1.time && t2.millitm == t1.millitm); 1243 sleepms_old(10L * SLEEPINIT); 1244 ftimex(&t2); 1245 if ((i = (int)(t2.time-t1.time)*1000 + t2.millitm-t1.millitm) < elapsed) 1246 elapsed = (i == 0) ? 1 : i; 1247 scalems = (long)((float)SLEEPINIT/(float)(elapsed) * scalems); 1248 cleartempmsg(); 1249 } 1250 if(ms > 10L * SLEEPINIT) { /* using ftime is probably more accurate */ 1251 ms /= 10; 1252 ftimex(&t1); 1253 for(;;) { 1254 if(keypressed()) break; 1255 ftimex(&t2); 1256 if ((long)((t2.time-t1.time)*1000 + t2.millitm-t1.millitm) >= ms) break; 1257 } 1258 } 1259 else 1260 if(!keypressed()) { 1261 ms *= scalems; 1262 while(ms-- >= 0); 1263 } 1264 sleepexit: 1265 tabmode = savetabmode; 1266 helpmode = savehelpmode; 1267 } 1268 1269 static void sleepms_new(long ms) 1270 { 1271 uclock_t next_time; 1272 uclock_t now = usec_clock(); 1273 next_time = now + ms*100; 1274 while ((now = usec_clock()) < next_time) 1275 if(keypressed()) break; 1276 } 1277 1278 void sleepms(long ms) 1279 { 1280 if(debugflag == 4020) 1281 sleepms_old(ms); 1282 else 1283 sleepms_new(ms); 1284 } 1285 1286 /* 1287 * wait until wait_time microseconds from the 1288 * last call has elapsed. 1289 */ 1290 #define MAX_INDEX 2 1291 static uclock_t next_time[MAX_INDEX]; 1292 void wait_until(int index, uclock_t wait_time) 1293 { 1294 if(debugflag == 4020) 1295 sleepms_old(wait_time); 1296 else 1297 { 1298 uclock_t now; 1299 while ( (now = usec_clock()) < next_time[index]) 1300 if(keypressed()) break; 1301 next_time[index] = now + wait_time*100; /* wait until this time next call */ 1302 } 1303 } 1304 1305 void reset_clock(void) 1306 { 1307 int i; 1308 restart_uclock(); 1309 for(i=0;i<MAX_INDEX;i++) 1310 next_time[i] = 0; 1311 } 1312 1313 #define LOG2 (float)0.693147180 1314 #define LOG32 (float)3.465735902 1315 1316 static FILE *snd_fp = NULL; 1317 1318 /* open sound file */ 1319 int snd_open(void) 1320 { 1321 static char soundname[] = {"sound001.txt"}; 1322 if((orbitsave&2) != 0 && snd_fp == NULL) 1323 { 1324 if((snd_fp = fopen(soundname,"w"))==NULL) 1325 { 1326 static FCODE msg[] = {"Can't open SOUND*.TXT"}; 1327 stopmsg(0,msg); 1328 } 1329 else 1330 { 1331 updatesavename(soundname); 1332 } 1333 } 1334 return(snd_fp != NULL); 1335 } 1336 1337 /* This routine plays a tone in the speaker and optionally writes a file 1338 if the orbitsave variable is turned on */ 1339 void w_snd(int tone) 1340 { 1341 if((orbitsave&2) != 0) 1342 { 1343 if(snd_open()) 1344 fprintf(snd_fp,"%-d\n",tone); 1345 } 1346 taborhelp = 0; 1347 if(!keypressed()) { /* keypressed calls mute() if TAB or F1 pressed */ 1348 /* must not then call soundoff(), else indexes out of synch */ 1349 /* if(20 < tone && tone < 15000) better limits? */ 1350 /* if(10 < tone && tone < 5000) better limits? */ 1351 if(soundon(tone)) { 1352 wait_until(0,orbit_delay); 1353 if(!taborhelp) /* kludge because wait_until() calls keypressed */ 1354 soundoff(); 1355 } 1356 } 1357 } 1358 1359 void snd_time_write(void) 1360 { 1361 if(snd_open()) 1362 { 1363 fprintf(snd_fp,"time=%-ld\n",(long)clock()*1000/CLK_TCK); 1364 } 1365 } 1366 1367 void close_snd(void) 1368 { 1369 if(snd_fp) 1370 fclose(snd_fp); 1371 snd_fp = NULL; 1372 } 1373 1374 static void _fastcall plotdorbit(double dx, double dy, int color) 1375 { 1376 int i, j, c; 1377 int save_sxoffs,save_syoffs; 1378 if (orbit_ptr >= 1500) return; 1379 i = (int)(dy * plotmx1 - dx * plotmx2); i += sxoffs; 1380 if (i < 0 || i >= sxdots) return; 1381 j = (int)(dx * plotmy1 - dy * plotmy2); j += syoffs; 1382 if (j < 0 || j >= sydots) return; 1383 save_sxoffs = sxoffs; 1384 save_syoffs = syoffs; 1385 sxoffs = syoffs = 0; 1386 /* save orbit value */ 1387 if(color == -1) 1388 { 1389 *(save_orbit + orbit_ptr++) = i; 1390 *(save_orbit + orbit_ptr++) = j; 1391 *(save_orbit + orbit_ptr++) = c = getcolor(i,j); 1392 putcolor(i,j,c^orbit_color); 1393 } 1394 else 1395 putcolor(i,j,color); 1396 sxoffs = save_sxoffs; 1397 syoffs = save_syoffs; 1398 if(debugflag == 4030) { 1399 if((soundflag&7) == 2) /* sound = x */ 1400 w_snd((int)(i*1000/xdots+basehertz)); 1401 else if((soundflag&7) > 2) /* sound = y or z */ 1402 w_snd((int)(j*1000/ydots+basehertz)); 1403 else if(orbit_delay > 0) 1404 { 1405 wait_until(0,orbit_delay); 1406 } 1407 } 1408 else { 1409 if((soundflag&7) == 2) /* sound = x */ 1410 w_snd((int)(i+basehertz)); 1411 else if((soundflag&7) == 3) /* sound = y */ 1412 w_snd((int)(j+basehertz)); 1413 else if((soundflag&7) == 4) /* sound = z */ 1414 w_snd((int)(i+j+basehertz)); 1415 else if(orbit_delay > 0) 1416 { 1417 wait_until(0,orbit_delay); 1418 } 1419 } 1420 1421 /* placing sleepms here delays each dot */ 1422 } 1423 1424 void iplot_orbit(long ix, long iy, int color) 1425 { 1426 plotdorbit((double)ix/fudge-xxmin,(double)iy/fudge-yymax,color); 1427 } 1428 1429 void plot_orbit(double real,double imag,int color) 1430 { 1431 plotdorbit(real-xxmin,imag-yymax,color); 1432 } 1433 1434 void scrub_orbit(void) 1435 { 1436 int i,j,c; 1437 int save_sxoffs,save_syoffs; 1438 mute(); 1439 save_sxoffs = sxoffs; 1440 save_syoffs = syoffs; 1441 sxoffs = syoffs = 0; 1442 while(orbit_ptr > 0) 1443 { 1444 c = *(save_orbit + --orbit_ptr); 1445 j = *(save_orbit + --orbit_ptr); 1446 i = *(save_orbit + --orbit_ptr); 1447 putcolor(i,j,c); 1448 } 1449 sxoffs = save_sxoffs; 1450 syoffs = save_syoffs; 1451 } 1452 1453 1454 int add_worklist(int xfrom, int xto, int xbegin, 1455 int yfrom, int yto, int ybegin, 1456 int pass, int sym) 1457 { 1458 if (num_worklist >= MAXCALCWORK) 1459 return(-1); 1460 worklist[num_worklist].xxstart = xfrom; 1461 worklist[num_worklist].xxstop = xto; 1462 worklist[num_worklist].xxbegin = xbegin; 1463 worklist[num_worklist].yystart = yfrom; 1464 worklist[num_worklist].yystop = yto; 1465 worklist[num_worklist].yybegin = ybegin; 1466 worklist[num_worklist].pass = pass; 1467 worklist[num_worklist].sym = sym; 1468 ++num_worklist; 1469 tidy_worklist(); 1470 return(0); 1471 } 1472 1473 static int _fastcall combine_worklist(void) /* look for 2 entries which can freely merge */ 1474 { 1475 int i,j; 1476 for (i=0; i<num_worklist; ++i) 1477 if (worklist[i].yystart == worklist[i].yybegin) 1478 for (j=i+1; j<num_worklist; ++j) 1479 if (worklist[j].sym == worklist[i].sym 1480 && worklist[j].yystart == worklist[j].yybegin 1481 && worklist[j].xxstart == worklist[j].xxbegin 1482 && worklist[i].pass == worklist[j].pass) 1483 { 1484 if ( worklist[i].xxstart == worklist[j].xxstart 1485 && worklist[i].xxbegin == worklist[j].xxbegin 1486 && worklist[i].xxstop == worklist[j].xxstop) 1487 { 1488 if (worklist[i].yystop+1 == worklist[j].yystart) 1489 { 1490 worklist[i].yystop = worklist[j].yystop; 1491 return(j); 1492 } 1493 if (worklist[j].yystop+1 == worklist[i].yystart) 1494 { 1495 worklist[i].yystart = worklist[j].yystart; 1496 worklist[i].yybegin = worklist[j].yybegin; 1497 return(j); 1498 } 1499 } 1500 if ( worklist[i].yystart == worklist[j].yystart 1501 && worklist[i].yybegin == worklist[j].yybegin 1502 && worklist[i].yystop == worklist[j].yystop) 1503 { 1504 if (worklist[i].xxstop+1 == worklist[j].xxstart) 1505 { 1506 worklist[i].xxstop = worklist[j].xxstop; 1507 return(j); 1508 } 1509 if (worklist[j].xxstop+1 == worklist[i].xxstart) 1510 { 1511 worklist[i].xxstart = worklist[j].xxstart; 1512 worklist[i].xxbegin = worklist[j].xxbegin; 1513 return(j); 1514 } 1515 } 1516 } 1517 return(0); /* nothing combined */ 1518 } 1519 1520 void tidy_worklist(void) /* combine mergeable entries, resort */ 1521 { 1522 int i,j; 1523 WORKLIST tempwork; 1524 while ((i=combine_worklist()) != 0) 1525 { /* merged two, delete the gone one */ 1526 while (++i < num_worklist) 1527 worklist[i-1] = worklist[i]; 1528 --num_worklist; 1529 } 1530 for (i=0; i<num_worklist; ++i) 1531 for (j=i+1; j<num_worklist; ++j) 1532 if (worklist[j].pass < worklist[i].pass 1533 || (worklist[j].pass == worklist[i].pass 1534 && (worklist[j].yystart < worklist[i].yystart 1535 || ( worklist[j].yystart == worklist[i].yystart 1536 && worklist[j].xxstart < worklist[i].xxstart)))) 1537 { /* dumb sort, swap 2 entries to correct order */ 1538 tempwork = worklist[i]; 1539 worklist[i] = worklist[j]; 1540 worklist[j] = tempwork; 1541 } 1542 } 1543 1544 1545 void get_julia_attractor (double real, double imag) 1546 { 1547 _LCMPLX lresult; 1548 _CMPLX result; 1549 int savper; 1550 long savmaxit; 1551 int i; 1552 1553 if (attractors == 0 && finattract == 0) /* not magnet & not requested */ 1554 return; 1555 1556 if (attractors >= N_ATTR) /* space for more attractors ? */ 1557 return; /* Bad luck - no room left ! */ 1558 1559 savper = periodicitycheck; 1560 savmaxit = maxit; 1561 periodicitycheck = 0; 1562 old.x = real; /* prepare for f.p orbit calc */ 1563 old.y = imag; 1564 tempsqrx = sqr(old.x); 1565 tempsqry = sqr(old.y); 1566 1567 lold.x = (long)real; /* prepare for int orbit calc */ 1568 lold.y = (long)imag; 1569 ltempsqrx = (long)tempsqrx; 1570 ltempsqry = (long)tempsqry; 1571 1572 lold.x = lold.x << bitshift; 1573 lold.y = lold.y << bitshift; 1574 ltempsqrx = ltempsqrx << bitshift; 1575 ltempsqry = ltempsqry << bitshift; 1576 1577 if (maxit < 500) /* we're going to try at least this hard */ 1578 maxit = 500; 1579 coloriter = 0; 1580 overflow = 0; 1581 while (++coloriter < maxit) 1582 if(curfractalspecific->orbitcalc() || overflow) 1583 break; 1584 if (coloriter >= maxit) /* if orbit stays in the lake */ 1585 { 1586 if (integerfractal) /* remember where it went to */ 1587 lresult = lnew; 1588 else 1589 result = new; 1590 for (i=0;i<10;i++) { 1591 overflow = 0; 1592 if(!curfractalspecific->orbitcalc() && !overflow) /* if it stays in the lake */ 1593 { /* and doesn't move far, probably */ 1594 if (integerfractal) /* found a finite attractor */ 1595 { 1596 if(labs(lresult.x-lnew.x) < lclosenuff 1597 && labs(lresult.y-lnew.y) < lclosenuff) 1598 { 1599 lattr[attractors] = lnew; 1600 attrperiod[attractors] = i+1; 1601 attractors++; /* another attractor - coloured lakes ! */ 1602 break; 1603 } 1604 } 1605 else 1606 { 1607 if(fabs(result.x-new.x) < closenuff 1608 && fabs(result.y-new.y) < closenuff) 1609 { 1610 attr[attractors] = new; 1611 attrperiod[attractors] = i+1; 1612 attractors++; /* another attractor - coloured lakes ! */ 1613 break; 1614 } 1615 } 1616 } else { 1617 break; 1618 } 1619 } 1620 } 1621 if(attractors==0) 1622 periodicitycheck = savper; 1623 maxit = savmaxit; 1624 } 1625 1626 1627 #define maxyblk 7 /* must match calcfrac.c */ 1628 #define maxxblk 202 /* must match calcfrac.c */ 1629 int ssg_blocksize(void) /* used by solidguessing and by zoom panning */ 1630 { 1631 int blocksize,i; 1632 /* blocksize 4 if <300 rows, 8 if 300-599, 16 if 600-1199, 32 if >=1200 */ 1633 blocksize=4; 1634 i=300; 1635 while(i<=ydots) 1636 { 1637 blocksize+=blocksize; 1638 i+=i; 1639 } 1640 /* increase blocksize if prefix array not big enough */ 1641 while(blocksize*(maxxblk-2)<xdots || blocksize*(maxyblk-2)*16<ydots) 1642 blocksize+=blocksize; 1643 return(blocksize); 1644 } 1645