File: common\zoom.c

    1 /*
    2     zoom.c - routines for zoombox manipulation and for panning
    3 
    4 */
    5 
    6 #include <string.h>
    7 
    8   /* see Fractint.c for a description of the "include"  hierarchy */
    9 #include "port.h"
   10 #include "prototyp.h"
   11 
   12 #define PIXELROUND 0.00001
   13 
   14 static void _fastcall zmo_calc(double, double, double *, double *, double);
   15 static void _fastcall zmo_calcbf(bf_t,bf_t,bf_t,bf_t,bf_t,bf_t,bf_t,bf_t,bf_t);
   16 static int  check_pan(void);
   17 static void fix_worklist(void);
   18 static void _fastcall move_row(int fromrow,int torow,int col);
   19 
   20 /* big number declarations */
   21 void calc_corner(bf_t target,bf_t p1,double p2,bf_t p3,double p4,bf_t p5)
   22 {
   23    bf_t btmp1, btmp2 ,btmp3;
   24    int saved; saved = save_stack();
   25    btmp1 = alloc_stack(rbflength+2);
   26    btmp2 = alloc_stack(rbflength+2);
   27    btmp3 = alloc_stack(rbflength+2);
   28 
   29    /* use target as temporary variable */
   30    floattobf(btmp3, p2);
   31    mult_bf(btmp1,btmp3,p3);
   32    mult_bf(btmp2,floattobf(target, p4),p5);
   33    add_bf(target,btmp1,btmp2);
   34    add_a_bf(target,p1);
   35    restore_stack(saved);
   36 }
   37 
   38 int boxcolor;
   39 
   40 #ifndef XFRACT
   41 void dispbox(void)
   42 {
   43    int i;
   44    int boxc = (colors-1)&boxcolor;
   45    unsigned char *values = (unsigned char *)boxvalues;
   46    int rgb[3];
   47    xorTARGA = 1;
   48    for(i=0;i<boxcount;i++)
   49    {
   50       if(istruecolor && truemode)
   51       {
   52          gettruecolor(boxx[i]-sxoffs,boxy[i]-syoffs,&rgb[0],&rgb[1],&rgb[2]);
   53          puttruecolor(boxx[i]-sxoffs,boxy[i]-syoffs,
   54                       rgb[0]^255,rgb[1]^255,rgb[2]^255);
   55       }
   56       else
   57          values[i] = (unsigned char)getcolor(boxx[i]-sxoffs,boxy[i]-syoffs);
   58    }
   59 /* There is an interaction between getcolor and putcolor, so separate them */
   60    if (!(istruecolor && truemode)) /* don't need this for truecolor with truemode set */
   61       for(i=0;i<boxcount;i++)
   62       {
   63          if (colors == 2)
   64             putcolor(boxx[i]-sxoffs,boxy[i]-syoffs,(1 - values[i]));
   65          else
   66             putcolor(boxx[i]-sxoffs,boxy[i]-syoffs,boxc);
   67       }
   68    xorTARGA = 0;
   69 }
   70 
   71 void clearbox(void)
   72 {
   73    int i;
   74    xorTARGA = 1;
   75    if(istruecolor && truemode)
   76    {
   77       dispbox();
   78    }
   79    else
   80    {
   81       unsigned char *values = (unsigned char *)boxvalues;
   82       for(i=0;i<boxcount;i++)
   83       {
   84          putcolor(boxx[i]-sxoffs,boxy[i]-syoffs,values[i]);
   85       }
   86    }
   87    xorTARGA = 0;
   88 }
   89 #endif
   90 
   91 void drawbox(int drawit)
   92 {
   93     struct coords tl,bl,tr,br; /* dot addr of topleft, botleft, etc */
   94     double tmpx,tmpy,dx,dy,rotcos,rotsin,ftemp1,ftemp2;
   95     double fxwidth,fxskew,fydepth,fyskew,fxadj;
   96     bf_t bffxwidth, bffxskew, bffydepth, bffyskew, bffxadj;
   97     int saved=0;
   98     if (zwidth==0) { /* no box to draw */
   99         if (boxcount!=0) { /* remove the old box from display */
  100             clearbox(); 
  101             boxcount = 0; }
  102         reset_zoom_corners();
  103         return; }
  104     if(bf_math)
  105     {
  106        saved = save_stack();
  107        bffxwidth = alloc_stack(rbflength+2);
  108        bffxskew  = alloc_stack(rbflength+2);
  109        bffydepth = alloc_stack(rbflength+2);
  110        bffyskew  = alloc_stack(rbflength+2);
  111        bffxadj   = alloc_stack(rbflength+2);
  112     }
  113     ftemp1 = PI*zrotate/72; /* convert to radians */
  114     rotcos = cos(ftemp1);   /* sin & cos of rotation */
  115     rotsin = sin(ftemp1);
  116 
  117     /* do some calcs just once here to reduce fp work a bit */
  118     fxwidth = sxmax-sx3rd;
  119     fxskew  = sx3rd-sxmin;
  120     fydepth = sy3rd-symax;
  121     fyskew  = symin-sy3rd;
  122     fxadj   = zwidth*zskew;
  123 
  124     if(bf_math)
  125     {
  126        /* do some calcs just once here to reduce fp work a bit */
  127        sub_bf(bffxwidth,bfsxmax,bfsx3rd);
  128        sub_bf(bffxskew,bfsx3rd,bfsxmin);
  129        sub_bf(bffydepth,bfsy3rd,bfsymax);
  130        sub_bf(bffyskew,bfsymin,bfsy3rd);
  131        floattobf(bffxadj, fxadj);
  132     }
  133 
  134     /* calc co-ords of topleft & botright corners of box */
  135     tmpx = zwidth/-2+fxadj; /* from zoombox center as origin, on xdots scale */
  136     tmpy = zdepth*finalaspectratio/2;
  137     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx; /* delta x to rotate topleft */
  138     dy = tmpy - (rotsin*tmpx + rotcos*tmpy); /* delta y to rotate topleft */
  139 
  140     /* calc co-ords of topleft */
  141     ftemp1 = zbx + dx + fxadj;
  142     ftemp2 = zby + dy/finalaspectratio;
  143 
  144     tl.x   = (int)(ftemp1*(dxsize+PIXELROUND)); /* screen co-ords */
  145     tl.y   = (int)(ftemp2*(dysize+PIXELROUND));
  146     xxmin  = sxmin + ftemp1*fxwidth + ftemp2*fxskew; /* real co-ords */
  147     yymax  = symax + ftemp2*fydepth + ftemp1*fyskew;
  148     if(bf_math)
  149     {
  150        calc_corner(bfxmin,bfsxmin,ftemp1,bffxwidth,ftemp2,bffxskew);
  151        calc_corner(bfymax,bfsymax,ftemp2,bffydepth,ftemp1,bffyskew);
  152     }
  153 
  154     /* calc co-ords of bottom right */
  155     ftemp1 = zbx + zwidth - dx - fxadj;
  156     ftemp2 = zby - dy/finalaspectratio + zdepth;
  157     br.x   = (int)(ftemp1*(dxsize+PIXELROUND));
  158     br.y   = (int)(ftemp2*(dysize+PIXELROUND));
  159     xxmax  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  160     yymin  = symax + ftemp2*fydepth + ftemp1*fyskew;
  161     if(bf_math)
  162     {
  163        calc_corner(bfxmax,bfsxmin,ftemp1,bffxwidth,ftemp2,bffxskew);
  164        calc_corner(bfymin,bfsymax,ftemp2,bffydepth,ftemp1,bffyskew);
  165     }
  166     /* do the same for botleft & topright */
  167     tmpx = zwidth/-2 - fxadj;
  168     tmpy = 0.0-tmpy;
  169     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx;
  170     dy = tmpy - (rotsin*tmpx + rotcos*tmpy);
  171     ftemp1 = zbx + dx - fxadj;
  172     ftemp2 = zby + dy/finalaspectratio + zdepth;
  173     bl.x   = (int)(ftemp1*(dxsize+PIXELROUND));
  174     bl.y   = (int)(ftemp2*(dysize+PIXELROUND));
  175     xx3rd  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  176     yy3rd  = symax + ftemp2*fydepth + ftemp1*fyskew;
  177     if(bf_math)
  178     {
  179        calc_corner(bfx3rd,bfsxmin,ftemp1,bffxwidth,ftemp2,bffxskew);
  180        calc_corner(bfy3rd,bfsymax,ftemp2,bffydepth,ftemp1,bffyskew);
  181        restore_stack(saved);
  182     }
  183     ftemp1 = zbx + zwidth - dx + fxadj;
  184     ftemp2 = zby - dy/finalaspectratio;
  185     tr.x   = (int)(ftemp1*(dxsize+PIXELROUND));
  186     tr.y   = (int)(ftemp2*(dysize+PIXELROUND));
  187 
  188     if (boxcount!=0) { /* remove the old box from display */
  189         clearbox(); 
  190         boxcount = 0; }
  191 
  192     if (drawit) { /* caller wants box drawn as well as co-ords calc'd */
  193 #ifndef XFRACT
  194         /* build the list of zoom box pixels */
  195         addbox(tl); addbox(tr);               /* corner pixels */
  196         addbox(bl); addbox(br);
  197         drawlines(tl,tr,bl.x-tl.x,bl.y-tl.y); /* top & bottom lines */
  198         drawlines(tl,bl,tr.x-tl.x,tr.y-tl.y); /* left & right lines */
199 #else 200 boxx[0] = tl.x + sxoffs; 201 boxy[0] = tl.y + syoffs; 202 boxx[1] = tr.x + sxoffs; 203 boxy[1] = tr.y + syoffs; 204 boxx[2] = br.x + sxoffs; 205 boxy[2] = br.y + syoffs; 206 boxx[3] = bl.x + sxoffs; 207 boxy[3] = bl.y + syoffs; 208 boxcount = 1;
209 #endif 210 dispbox(); 211 } 212 } 213 214 void _fastcall drawlines(struct coords fr, struct coords to, 215 int dx, int dy) 216 { int xincr,yincr,ctr; 217 int altctr,altdec,altinc; 218 struct coords tmpp,line1,line2; 219 220 if (abs(to.x-fr.x) > abs(to.y-fr.y)) { /* delta.x > delta.y */ 221 if (fr.x>to.x) { /* swap so from.x is < to.x */ 222 tmpp = fr; fr = to; to = tmpp; } 223 xincr = (to.x-fr.x)*4/sxdots+1; /* do every 1st, 2nd, 3rd, or 4th dot */ 224 ctr = (to.x-fr.x-1)/xincr; 225 altdec = abs(to.y-fr.y)*xincr; 226 altinc = to.x-fr.x; 227 altctr = altinc/2; 228 yincr = (to.y>fr.y)?1:-1; 229 line2.x = (line1.x = fr.x) + dx; 230 line2.y = (line1.y = fr.y) + dy; 231 while (--ctr>=0) { 232 line1.x += xincr; 233 line2.x += xincr; 234 altctr -= altdec; 235 while (altctr<0) { 236 altctr += altinc; 237 line1.y += yincr; 238 line2.y += yincr; 239 } 240 addbox(line1); 241 addbox(line2); 242 } 243 } 244 245 else { /* delta.y > delta.x */ 246 if (fr.y>to.y) { /* swap so from.y is < to.y */ 247 tmpp = fr; fr = to; to = tmpp; } 248 yincr = (to.y-fr.y)*4/sydots+1; /* do every 1st, 2nd, 3rd, or 4th dot */ 249 ctr = (to.y-fr.y-1)/yincr; 250 altdec = abs(to.x-fr.x)*yincr; 251 altinc = to.y-fr.y; 252 altctr = altinc/2; 253 xincr = (to.x>fr.x) ? 1 : -1; 254 line2.x = (line1.x = fr.x) + dx; 255 line2.y = (line1.y = fr.y) + dy; 256 while (--ctr>=0) { 257 line1.y += yincr; 258 line2.y += yincr; 259 altctr -= altdec; 260 while (altctr<0) { 261 altctr += altinc; 262 line1.x += xincr; 263 line2.x += xincr; 264 } 265 addbox(line1); 266 addbox(line2); 267 } 268 } 269 } 270 271 void _fastcall addbox(struct coords point) 272 { 273 point.x += sxoffs; 274 point.y += syoffs; 275 if (point.x >= 0 && point.x < sxdots && 276 point.y >= 0 && point.y < sydots) { 277 boxx[boxcount] = point.x; 278 boxy[boxcount] = point.y; 279 ++boxcount; 280 } 281 } 282 283 void moveboxf(double dx, double dy) 284 { int align,row,col; 285 align = check_pan(); 286 if (dx!=0.0) { 287 if ((zbx += dx) + zwidth/2 < 0) /* center must stay onscreen */ 288 zbx = zwidth/-2; 289 if (zbx + zwidth/2 > 1) 290 zbx = 1.0 - zwidth/2; 291 if (align != 0 292 && ((col = (int)(zbx*(dxsize+PIXELROUND))) & (align-1)) != 0) { 293 if (dx > 0) col += align; 294 col -= col & (align-1); /* adjust col to pass alignment */ 295 zbx = (double)col/dxsize; } 296 } 297 if (dy!=0.0) { 298 if ((zby += dy) + zdepth/2 < 0) 299 zby = zdepth/-2; 300 if (zby + zdepth/2 > 1) 301 zby = 1.0 - zdepth/2; 302 if (align != 0 303 && ((row = (int)(zby*(dysize+PIXELROUND))) & (align-1)) != 0) { 304 if (dy > 0) row += align; 305 row -= row & (align-1); 306 zby = (double)row/dysize; } 307 } 308 #ifndef XFRACT 309 if (video_scroll != 0) { /* scroll screen center to the box center */ 310 col = (int)((zbx + zwidth/2)*(dxsize + PIXELROUND)) + sxoffs; 311 row = (int)((zby + zdepth/2)*(dysize + PIXELROUND)) + syoffs; 312 switch (zscroll) { 313 case 0: /* fixed - screen center fixed to the zoombox center */ 314 scroll_center(col,row); 315 break; 316 case 1: /* relaxed - as the zoombox center leaves the screen */ 317 if ((col -= video_startx) > 0 && (col -= vesa_xres - 1) < 0) 318 col = 0; 319 if ((row -= video_starty) > 0 && (row -= vesa_yres - 1) < 0) 320 row = 0; 321 if (col != 0 || row != 0) 322 scroll_relative(col, row); 323 break; 324 } 325 } 326 #endif 327 } 328 329 static void _fastcall chgboxf(double dwidth, double ddepth) 330 { 331 if (zwidth+dwidth > 1) 332 dwidth = 1.0-zwidth; 333 if (zwidth+dwidth < 0.05) 334 dwidth = 0.05-zwidth; 335 zwidth += dwidth; 336 if (zdepth+ddepth > 1) 337 ddepth = 1.0-zdepth; 338 if (zdepth+ddepth < 0.05) 339 ddepth = 0.05-zdepth; 340 zdepth += ddepth; 341 moveboxf(dwidth/-2,ddepth/-2); /* keep it centered & check limits */ 342 } 343 344 void resizebox(int steps) 345 { 346 double deltax,deltay; 347 if (zdepth*screenaspect > zwidth) { /* box larger on y axis */ 348 deltay = steps * 0.036 / screenaspect; 349 deltax = zwidth * deltay / zdepth; 350 } 351 else { /* box larger on x axis */ 352 deltax = steps * 0.036; 353 deltay = zdepth * deltax / zwidth; 354 } 355 chgboxf(deltax,deltay); 356 } 357 358 void chgboxi(int dw, int dd) 359 { /* change size by pixels */ 360 chgboxf( (double)dw/dxsize, (double)dd/dysize ); 361 } 362 #ifdef C6
363 #pragma optimize("e",off) /* MSC 6.00A messes up next rtn with "e" on */
364 #endif 365 366 extern void show_three_bf(); 367 368 static void _fastcall zmo_calcbf(bf_t bfdx, bf_t bfdy, 369 bf_t bfnewx, bf_t bfnewy,bf_t bfplotmx1, bf_t bfplotmx2, bf_t bfplotmy1, 370 bf_t bfplotmy2, bf_t bfftemp) 371 { 372 bf_t btmp1, btmp2, btmp3, btmp4, btempx, btempy ; 373 bf_t btmp2a, btmp4a; 374 int saved; saved = save_stack(); 375 376 btmp1 = alloc_stack(rbflength+2); 377 btmp2 = alloc_stack(rbflength+2); 378 btmp3 = alloc_stack(rbflength+2); 379 btmp4 = alloc_stack(rbflength+2); 380 btmp2a = alloc_stack(rbflength+2); 381 btmp4a = alloc_stack(rbflength+2); 382 btempx = alloc_stack(rbflength+2); 383 btempy = alloc_stack(rbflength+2); 384 385 /* calc cur screen corner relative to zoombox, when zoombox co-ords 386 are taken as (0,0) topleft thru (1,1) bottom right */ 387 388 /* tempx = dy * plotmx1 - dx * plotmx2; */ 389 mult_bf(btmp1,bfdy,bfplotmx1); 390 mult_bf(btmp2,bfdx,bfplotmx2); 391 sub_bf(btempx,btmp1,btmp2); 392 393 /* tempy = dx * plotmy1 - dy * plotmy2; */ 394 mult_bf(btmp1,bfdx,bfplotmy1); 395 mult_bf(btmp2,bfdy,bfplotmy2); 396 sub_bf(btempy,btmp1,btmp2); 397 398 /* calc new corner by extending from current screen corners */ 399 /* *newx = sxmin + tempx*(sxmax-sx3rd)/ftemp + tempy*(sx3rd-sxmin)/ftemp; */ 400 sub_bf(btmp1,bfsxmax,bfsx3rd); 401 mult_bf(btmp2,btempx,btmp1); 402 /* show_three_bf("fact1",btempx,"fact2",btmp1,"prod ",btmp2,70); */ 403 div_bf(btmp2a,btmp2,bfftemp); 404 /* show_three_bf("num ",btmp2,"denom",bfftemp,"quot ",btmp2a,70); */ 405 sub_bf(btmp3,bfsx3rd,bfsxmin); 406 mult_bf(btmp4,btempy,btmp3); 407 div_bf(btmp4a,btmp4,bfftemp); 408 add_bf(bfnewx,bfsxmin,btmp2a); 409 add_a_bf(bfnewx,btmp4a); 410 411 /* *newy = symax + tempy*(sy3rd-symax)/ftemp + tempx*(symin-sy3rd)/ftemp; */ 412 sub_bf(btmp1,bfsy3rd,bfsymax); 413 mult_bf(btmp2,btempy,btmp1); 414 div_bf(btmp2a,btmp2,bfftemp); 415 sub_bf(btmp3,bfsymin,bfsy3rd); 416 mult_bf(btmp4,btempx,btmp3); 417 div_bf(btmp4a,btmp4,bfftemp); 418 add_bf(bfnewy,bfsymax,btmp2a); 419 add_a_bf(bfnewy,btmp4a); 420 restore_stack(saved); 421 } 422 423 static void _fastcall zmo_calc(double dx, double dy, double *newx, double *newy, double ftemp) 424 { 425 double tempx,tempy; 426 /* calc cur screen corner relative to zoombox, when zoombox co-ords 427 are taken as (0,0) topleft thru (1,1) bottom right */ 428 tempx = dy * plotmx1 - dx * plotmx2; 429 tempy = dx * plotmy1 - dy * plotmy2; 430 431 /* calc new corner by extending from current screen corners */ 432 *newx = sxmin + tempx*(sxmax-sx3rd)/ftemp + tempy*(sx3rd-sxmin)/ftemp; 433 *newy = symax + tempy*(sy3rd-symax)/ftemp + tempx*(symin-sy3rd)/ftemp; 434 } 435 436 void zoomoutbf(void) /* for ctl-enter, calc corners for zooming out */ 437 { 438 /* (xxmin,yymax), etc, are already set to zoombox corners; 439 (sxmin,symax), etc, are still the screen's corners; 440 use the same logic as plot_orbit stuff to first calculate current screen 441 corners relative to the zoombox, as if the zoombox were a square with 442 upper left (0,0) and width/depth 1; ie calc the current screen corners 443 as if plotting them from the zoombox; 444 then extend these co-ords from current real screen corners to get 445 new actual corners 446 */ 447 bf_t savbfxmin,savbfymax,bfftemp; 448 bf_t tmp1, tmp2, tmp3, tmp4, tmp5, tmp6,bfplotmx1,bfplotmx2,bfplotmy1,bfplotmy2; 449 int saved; 450 saved = save_stack(); 451 savbfxmin = alloc_stack(rbflength+2); 452 savbfymax = alloc_stack(rbflength+2); 453 bfftemp = alloc_stack(rbflength+2); 454 tmp1 = alloc_stack(rbflength+2); 455 tmp2 = alloc_stack(rbflength+2); 456 tmp3 = alloc_stack(rbflength+2); 457 tmp4 = alloc_stack(rbflength+2); 458 tmp5 = alloc_stack(rbflength+2); 459 tmp6 = alloc_stack(rbflength+2); 460 bfplotmx1 = alloc_stack(rbflength+2); 461 bfplotmx2 = alloc_stack(rbflength+2); 462 bfplotmy1 = alloc_stack(rbflength+2); 463 bfplotmy2 = alloc_stack(rbflength+2); 464 /* ftemp = (yymin-yy3rd)*(xx3rd-xxmin) - (xxmax-xx3rd)*(yy3rd-yymax); */ 465 sub_bf(tmp1,bfymin,bfy3rd); 466 sub_bf(tmp2,bfx3rd,bfxmin); 467 sub_bf(tmp3,bfxmax,bfx3rd); 468 sub_bf(tmp4,bfy3rd,bfymax); 469 mult_bf(tmp5,tmp1,tmp2); 470 mult_bf(tmp6,tmp3,tmp4); 471 sub_bf(bfftemp,tmp5,tmp6); 472 /* plotmx1 = (xx3rd-xxmin); */ ; /* reuse the plotxxx vars is safe */ 473 copy_bf(bfplotmx1,tmp2); 474 /* plotmx2 = (yy3rd-yymax); */ 475 copy_bf(bfplotmx2,tmp4); 476 /* plotmy1 = (yymin-yy3rd); */ 477 copy_bf(bfplotmy1,tmp1); 478 /* plotmy2 = (xxmax-xx3rd); */; 479 copy_bf(bfplotmy2,tmp3); 480 481 /* savxxmin = xxmin; savyymax = yymax; */ 482 copy_bf(savbfxmin,bfxmin); copy_bf(savbfymax,bfymax); 483 484 sub_bf(tmp1,bfsxmin,savbfxmin); sub_bf(tmp2,bfsymax,savbfymax); 485 zmo_calcbf(tmp1,tmp2,bfxmin,bfymax,bfplotmx1,bfplotmx2,bfplotmy1, 486 bfplotmy2,bfftemp); 487 sub_bf(tmp1,bfsxmax,savbfxmin); sub_bf(tmp2,bfsymin,savbfymax); 488 zmo_calcbf(tmp1,tmp2,bfxmax,bfymin,bfplotmx1,bfplotmx2,bfplotmy1, 489 bfplotmy2,bfftemp); 490 sub_bf(tmp1,bfsx3rd,savbfxmin); sub_bf(tmp2,bfsy3rd,savbfymax); 491 zmo_calcbf(tmp1,tmp2,bfx3rd,bfy3rd,bfplotmx1,bfplotmx2,bfplotmy1, 492 bfplotmy2,bfftemp); 493 restore_stack(saved); 494 } 495 496 void zoomoutdbl(void) /* for ctl-enter, calc corners for zooming out */ 497 { 498 /* (xxmin,yymax), etc, are already set to zoombox corners; 499 (sxmin,symax), etc, are still the screen's corners; 500 use the same logic as plot_orbit stuff to first calculate current screen 501 corners relative to the zoombox, as if the zoombox were a square with 502 upper left (0,0) and width/depth 1; ie calc the current screen corners 503 as if plotting them from the zoombox; 504 then extend these co-ords from current real screen corners to get 505 new actual corners 506 */ 507 double savxxmin,savyymax,ftemp; 508 ftemp = (yymin-yy3rd)*(xx3rd-xxmin) - (xxmax-xx3rd)*(yy3rd-yymax); 509 plotmx1 = (xx3rd-xxmin); /* reuse the plotxxx vars is safe */ 510 plotmx2 = (yy3rd-yymax); 511 plotmy1 = (yymin-yy3rd); 512 plotmy2 = (xxmax-xx3rd); 513 savxxmin = xxmin; savyymax = yymax; 514 zmo_calc(sxmin-savxxmin,symax-savyymax,&xxmin,&yymax,ftemp); 515 zmo_calc(sxmax-savxxmin,symin-savyymax,&xxmax,&yymin,ftemp); 516 zmo_calc(sx3rd-savxxmin,sy3rd-savyymax,&xx3rd,&yy3rd,ftemp); 517 } 518 519 void zoomout(void) /* for ctl-enter, calc corners for zooming out */ 520 { 521 if(bf_math) 522 { 523 zoomoutbf(); 524 } 525 else 526 zoomoutdbl(); 527 } 528 529 #ifdef C6
530 #pragma optimize("e",on) /* back to normal */
531 #endif 532 533 void aspectratio_crop(float oldaspect,float newaspect) 534 { 535 double ftemp,xmargin,ymargin; 536 if (newaspect > oldaspect) { /* new ratio is taller, crop x */ 537 ftemp = (1.0 - oldaspect / newaspect) / 2; 538 xmargin = (xxmax - xx3rd) * ftemp; 539 ymargin = (yymin - yy3rd) * ftemp; 540 xx3rd += xmargin; 541 yy3rd += ymargin; 542 } 543 else { /* new ratio is wider, crop y */ 544 ftemp = (1.0 - newaspect / oldaspect) / 2; 545 xmargin = (xx3rd - xxmin) * ftemp; 546 ymargin = (yy3rd - yymax) * ftemp; 547 xx3rd -= xmargin; 548 yy3rd -= ymargin; 549 } 550 xxmin += xmargin; 551 yymax += ymargin; 552 xxmax -= xmargin; 553 yymin -= ymargin; 554 } 555 556 static int check_pan(void) /* return 0 if can't, alignment requirement if can */ 557 { int i,j; 558 if ((calc_status != 2 && calc_status != 4) || evolving) 559 return(0); /* not resumable, not complete */ 560 if ( curfractalspecific->calctype != StandardFractal 561 && curfractalspecific->calctype != calcmand 562 && curfractalspecific->calctype != calcmandfp 563 && curfractalspecific->calctype != lyapunov 564 && curfractalspecific->calctype != calcfroth) 565 return(0); /* not a worklist-driven type */ 566 if (zwidth != 1.0 || zdepth != 1.0 || zskew != 0.0 || zrotate != 0.0) 567 return(0); /* not a full size unrotated unskewed zoombox */ 568 if (stdcalcmode == 't') 569 return(0); /* tesselate, can't do it */ 570 if (stdcalcmode == 'd') 571 return(0); /* diffusion scan: can't do it either */ 572 if (stdcalcmode == 'o') 573 return(0); /* orbits, can't do it */ 574 575 /* can pan if we get this far */ 576 577 if (calc_status == 4) 578 return(1); /* image completed, align on any pixel */ 579 if (potflag && pot16bit) 580 return(1); /* 1 pass forced so align on any pixel */ 581 if (stdcalcmode == 'b') 582 return(1); /* btm, align on any pixel */ 583 if (stdcalcmode != 'g' || (curfractalspecific->flags&NOGUESS)) { 584 if (stdcalcmode == '2' || stdcalcmode == '3') /* align on even pixel for 2pass */ 585 return(2); 586 return(1); /* assume 1pass */ 587 } 588 /* solid guessing */ 589 start_resume(); 590 get_resume(sizeof(num_worklist),&num_worklist,sizeof(worklist),worklist,0); 591 /* don't do end_resume! we're just looking */ 592 i = 9; 593 for (j=0; j<num_worklist; ++j) /* find lowest pass in any pending window */ 594 if (worklist[j].pass < i) 595 i = worklist[j].pass; 596 j = ssg_blocksize(); /* worst-case alignment requirement */ 597 while (--i >= 0) 598 j = j>>1; /* reduce requirement */ 599 return(j); 600 } 601 602 static void _fastcall move_row(int fromrow,int torow,int col) 603 /* move a row on the screen */ 604 { int startcol,endcol,tocol; 605 memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */ 606 if (fromrow >= 0 && fromrow < ydots) { 607 tocol = startcol = 0; 608 endcol = xdots-1; 609 if (col < 0) { 610 tocol -= col; 611 endcol += col; } 612 if (col > 0) 613 startcol += col; 614 get_line(fromrow,startcol,endcol,(BYTE *)&dstack[tocol]); 615 } 616 put_line(torow,0,xdots-1,(BYTE *)dstack); 617 } 618 619 int init_pan_or_recalc(int do_zoomout) /* decide to recalc, or to chg worklist & pan */ 620 { int i,j,row,col,y,alignmask,listfull; 621 if (zwidth == 0.0) 622 return(0); /* no zoombox, leave calc_status as is */ 623 /* got a zoombox */ 624 if ((alignmask=check_pan()-1) < 0 || evolving) { 625 calc_status = 0; /* can't pan, trigger recalc */ 626 return(0); } 627 if (zbx == 0.0 && zby == 0.0) { 628 clearbox(); 629 return(0); } /* box is full screen, leave calc_status as is */ 630 col = (int)(zbx*(dxsize+PIXELROUND)); /* calc dest col,row of topleft pixel */ 631 row = (int)(zby*(dysize+PIXELROUND)); 632 if (do_zoomout) { /* invert row and col */ 633 row = 0-row; 634 col = 0-col; } 635 if ((row&alignmask) != 0 || (col&alignmask) != 0) { 636 calc_status = 0; /* not on useable pixel alignment, trigger recalc */ 637 return(0); } 638 /* pan */ 639 num_worklist = 0; 640 if (calc_status == 2) { 641 start_resume(); 642 get_resume(sizeof(num_worklist),&num_worklist,sizeof(worklist),worklist,0); 643 } /* don't do end_resume! we might still change our mind */ 644 /* adjust existing worklist entries */ 645 for (i=0; i<num_worklist; ++i) { 646 worklist[i].yystart -= row; 647 worklist[i].yystop -= row; 648 worklist[i].yybegin -= row; 649 worklist[i].xxstart -= col; 650 worklist[i].xxstop -= col; 651 worklist[i].xxbegin -= col; 652 } 653 /* add worklist entries for the new edges */ 654 listfull = i = 0; 655 j = ydots-1; 656 if (row < 0) { 657 listfull |= add_worklist(0,xdots-1,0,0,0-row-1,0,0,0); 658 i = 0 - row; } 659 if (row > 0) { 660 listfull |= add_worklist(0,xdots-1,0,ydots-row,ydots-1,ydots-row,0,0); 661 j = ydots - row - 1; } 662 if (col < 0) 663 listfull |= add_worklist(0,0-col-1,0,i,j,i,0,0); 664 if (col > 0) 665 listfull |= add_worklist(xdots-col,xdots-1,xdots-col,i,j,i,0,0); 666 if (listfull != 0) { 667 static FCODE msg[] = {"\ 668 Tables full, can't pan current image.\n\ 669 Cancel resumes old image, continue pans and calculates a new one."}; 670 if (stopmsg(2,msg)) { 671 zwidth = 0; /* cancel the zoombox */ 672 drawbox(1); } 673 else 674 calc_status = 0; /* trigger recalc */ 675 return(0); } 676 /* now we're committed */ 677 calc_status = 2; 678 clearbox(); 679 if (row > 0) /* move image up */ 680 for (y=0; y<ydots; ++y) move_row(y+row,y,col); 681 else /* move image down */ 682 for (y=ydots; --y>=0;) move_row(y+row,y,col); 683 fix_worklist(); /* fixup any out of bounds worklist entries */ 684 alloc_resume(sizeof(worklist)+20,2); /* post the new worklist */ 685 put_resume(sizeof(num_worklist),&num_worklist,sizeof(worklist),worklist,0); 686 return(0); 687 } 688 689 static void _fastcall restart_window(int wknum) 690 /* force a worklist entry to restart */ 691 { int yfrom,yto,xfrom,xto; 692 if ((yfrom = worklist[wknum].yystart) < 0) yfrom = 0; 693 if ((xfrom = worklist[wknum].xxstart) < 0) xfrom = 0; 694 if ((yto = worklist[wknum].yystop) >= ydots) yto = ydots - 1; 695 if ((xto = worklist[wknum].xxstop) >= xdots) xto = xdots - 1; 696 memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */ 697 while (yfrom <= yto) 698 put_line(yfrom++,xfrom,xto,(BYTE *)dstack); 699 worklist[wknum].sym = worklist[wknum].pass = 0; 700 worklist[wknum].yybegin = worklist[wknum].yystart; 701 worklist[wknum].xxbegin = worklist[wknum].xxstart; 702 } 703 704 static void fix_worklist(void) /* fix out of bounds and symmetry related stuff */ 705 { int i,j,k; 706 WORKLIST *wk; 707 for (i=0; i<num_worklist; ++i) { 708 wk = &worklist[i]; 709 if ( wk->yystart >= ydots || wk->yystop < 0 710 || wk->xxstart >= xdots || wk->xxstop < 0) { /* offscreen, delete */ 711 for (j=i+1; j<num_worklist; ++j) 712 worklist[j-1] = worklist[j]; 713 --num_worklist; 714 --i; 715 continue; } 716 if (wk->yystart < 0) { /* partly off top edge */ 717 if ((wk->sym&1) == 0) { /* no sym, easy */ 718 wk->yystart = 0; 719 wk->xxbegin = 0; } 720 else { /* xaxis symmetry */ 721 if ((j = wk->yystop + wk->yystart) > 0 722 && num_worklist < MAXCALCWORK) { /* split the sym part */ 723 worklist[num_worklist] = worklist[i]; 724 worklist[num_worklist].yystart = 0; 725 worklist[num_worklist++].yystop = j; 726 wk->yystart = j+1; } 727 else 728 wk->yystart = 0; 729 restart_window(i); /* restart the no-longer sym part */ 730 } 731 } 732 if (wk->yystop >= ydots) { /* partly off bottom edge */ 733 j = ydots-1; 734 if ((wk->sym&1) != 0) { /* uses xaxis symmetry */ 735 if ((k = wk->yystart + (wk->yystop - j)) < j) { 736 if (num_worklist >= MAXCALCWORK) /* no room to split */ 737 restart_window(i); 738 else { /* split it */ 739 worklist[num_worklist] = worklist[i]; 740 worklist[num_worklist].yystart = k; 741 worklist[num_worklist++].yystop = j; 742 j = k-1; } 743 } 744 wk->sym &= -1 - 1; } 745 wk->yystop = j; } 746 if (wk->xxstart < 0) { /* partly off left edge */ 747 if ((wk->sym&2) == 0) /* no sym, easy */ 748 wk->xxstart = 0; 749 else { /* yaxis symmetry */ 750 if ((j = wk->xxstop + wk->xxstart) > 0 751 && num_worklist < MAXCALCWORK) { /* split the sym part */ 752 worklist[num_worklist] = worklist[i]; 753 worklist[num_worklist].xxstart = 0; 754 worklist[num_worklist++].xxstop = j; 755 wk->xxstart = j+1; } 756 else 757 wk->xxstart = 0; 758 restart_window(i); /* restart the no-longer sym part */ 759 } 760 } 761 if (wk->xxstop >= xdots) { /* partly off right edge */ 762 j = xdots-1; 763 if ((wk->sym&2) != 0) { /* uses xaxis symmetry */ 764 if ((k = wk->xxstart + (wk->xxstop - j)) < j) { 765 if (num_worklist >= MAXCALCWORK) /* no room to split */ 766 restart_window(i); 767 else { /* split it */ 768 worklist[num_worklist] = worklist[i]; 769 worklist[num_worklist].xxstart = k; 770 worklist[num_worklist++].xxstop = j; 771 j = k-1; } 772 } 773 wk->sym &= -1 - 2; } 774 wk->xxstop = j; } 775 if (wk->yybegin < wk->yystart) wk->yybegin = wk->yystart; 776 if (wk->yybegin > wk->yystop) wk->yybegin = wk->yystop; 777 if (wk->xxbegin < wk->xxstart) wk->xxbegin = wk->xxstart; 778 if (wk->xxbegin > wk->xxstop) wk->xxbegin = wk->xxstop; 779 } 780 tidy_worklist(); /* combine where possible, re-sort */ 781 } 782