File: common\loadfdos.c

    1 /*
    2     loadfdos.c - subroutine of loadfile.c (read_overlay) which sets
    3                  up video (mode, screen size).
    4     This module is linked as an overlay, should only be called from loadfile.c
    5 
    6     This code was split to a separate module to isolate the DOS only aspects
    7     of loading an image.  get_video_mode should return with:
    8       return code 0 for ok, -1 for error or cancelled by user
    9       video parameters setup for the mainline, in the dos case this means
   10         setting initmode to video mode, based on this fractint.c will set up
   11         for and call setvideomode
   12       set viewwindow on if file going to be loaded into a view smaller than
   13         physical screen, in this case also set viewreduction, viewxdots,
   14         viewydots, and finalaspectratio
   15       set skipxdots and skipydots, to 0 if all pixels are to be loaded,
   16         to 1 for every 2nd pixel, 2 for every 3rd, etc
   17 
   18     In WinFract, at least initially, get_video_mode can do just the
   19     following:
   20       set overall image x & y dimensions (sxdots and sydots) to filexdots
   21         and fileydots (note that filecolors is the number of colors in the
   22         gif, not sure if that is of any use...)
   23       if current window smaller than new sxdots and sydots, use scroll bars,
   24         if larger perhaps reduce the window size? whatever
   25       set viewwindow to 0 (no need? it always is for now in windows vsn?)
   26       set finalaspectratio to .75 (ditto?)
   27       set skipxdots and skipydots to 0
   28       return 0
   29 
   30 */
   31 
   32 #include <string.h>
   33   /* see Fractint.c for a description of the "include"  hierarchy */
   34 #include "port.h"
   35 #include "prototyp.h"
   36 #include "helpdefs.h"
   37 
   38 /* routines in this module      */
   39 
   40 #ifndef XFRACT
   41 static int    vidcompare(VOIDCONSTPTR ,VOIDCONSTPTR );
   42 static void   format_item(int,char *);
   43 static int    check_modekey(int,int);
   44 static void   format_vid_inf(int i,char *err,char *buf);
   45 #endif
   46 static double vid_aspect(int tryxdots,int tryydots);
   47 
   48 struct vidinf {
   49    int entnum;     /* videoentry subscript */
   50    unsigned flags; /* flags for sort's compare, defined below */
   51    };
   52 /* defines for flags; done this way instead of bit union to ensure ordering;
   53    these bits represent the sort sequence for video mode list */
   54 #define VI_EXACT 0x8000 /* unless the one and only exact match */
   55 #define VI_NOKEY   512  /* if no function key assigned */
   56 #define VI_DISK1   256  /* disk video and size not exact */
   57 #define VI_SSMALL  128  /* screen smaller than file's screen */
   58 #define VI_SBIG     64  /* screen bigger than file's screen */
   59 #define VI_VSMALL   32  /* screen smaller than file's view */
   60 #define VI_VBIG     16  /* screen bigger than file's view */
   61 #define VI_CSMALL    8  /* mode has too few colors */
   62 #define VI_CBIG      4  /* mode has excess colors */
   63 #define VI_DISK2     2  /* disk video */
   64 #define VI_ASPECT    1  /* aspect ratio bad */
   65 
   66 #ifndef XFRACT
   67 static int vidcompare(VOIDCONSTPTR p1,VOIDCONSTPTR p2)
   68 {
   69    struct vidinf CONST *ptr1,*ptr2;
   70    ptr1 = (struct vidinf CONST *)p1;
   71    ptr2 = (struct vidinf CONST *)p2;
   72    if (ptr1->flags < ptr2->flags) return(-1);
   73    if (ptr1->flags > ptr2->flags) return(1);
   74    if (vidtbl[ptr1->entnum].keynum < vidtbl[ptr2->entnum].keynum) return(-1);
   75    if (vidtbl[ptr1->entnum].keynum > vidtbl[ptr2->entnum].keynum) return(1);
   76    if (ptr1->entnum < ptr2->entnum) return(-1);
   77    return(1);
   78 }
   79 
   80 static void format_vid_inf(int i,char *err,char *buf)
   81 {
   82    char kname[5];
   83    far_memcpy((char far *)&videoentry,(char far *)&vidtbl[i],
   84               sizeof(videoentry));
   85    vidmode_keyname(videoentry.keynum,kname);
   86    sprintf(buf,"%-5s %-25s %-4s %5d %5d %3d %-25s",  /* 78 chars */
   87            kname, videoentry.name, err,
   88            videoentry.xdots, videoentry.ydots,
   89            videoentry.colors, videoentry.comment);
   90    videoentry.xdots = 0; /* so tab_display knows to display nothing */
   91 }
   92 #endif
   93 
   94 static double vid_aspect(int tryxdots,int tryydots)
   95 {  /* calc resulting aspect ratio for specified dots in current mode */
   96    return (double)tryydots / (double)tryxdots
   97         * (double)videoentry.xdots / (double)videoentry.ydots
   98         * screenaspect;
   99    }
  100 
  101 #ifndef XFRACT
  102 static struct vidinf *vidptr;
  103 #endif
  104 
  105 int get_video_mode(struct fractal_info *info,struct ext_blk_3 *blk_3_info)
  106 {
  107    static FCODE o_hdg2[]={"key...name......................err...xdot..ydot.clr.comment.................."};
  108    static FCODE o_warning[]={"\nWARNING: non-standard aspect ratio; loading will change your <v>iew settings"};
  109    static FCODE o_select_msg[]={"\
  110 Select a video mode.  Use the cursor keypad to move the pointer.\n\
  111 Press ENTER for selected mode, or use a video mode function key.\n\
  112 Press F1 for help, "};
  113    char far *hdg2, far *warning, far *select_msg, far *ptr;
  114    struct vidinf vid[MAXVIDEOMODES];
  115    int i,j;
  116    int gotrealmode;
  117    double ftemp,ftemp2;
  118    unsigned tmpflags;
  119 
  120    int tmpxdots,tmpydots;
  121    float tmpreduce;
  122 #ifndef XFRACT
  123    char *nameptr;
  124    int  *attributes;
  125    int oldhelpmode;
  126 #endif
  127    VIDEOINFO *vident;
  128 
  129    /* save overlayed strings to extraseg memory */
  130    ptr = (char far *)MK_FP(extraseg,ENDVID);  /* ENDVID is to avoid videotable */
  131    hdg2 = ptr;
  132    ptr += sizeof(o_hdg2);
  133    warning = ptr;
  134    ptr += sizeof(o_warning);
  135    select_msg = ptr;
  136    far_strcpy(hdg2,o_hdg2);
  137    far_strcpy(warning,o_warning);
  138    far_strcpy(select_msg,o_select_msg);
  139 
  140    initmode = -1;
  141    load_fractint_cfg(0); /* get fractint.cfg into *vidtbl (== extraseg) */
  142 
  143    /* try to change any VESA entries to fit the loaded image size */
  144    if (virtual && video_vram && initmode == -1) {
  145       unsigned long vram = (unsigned long)video_vram << 16,
  146                     need = (unsigned long)info->xdots * info->ydots;
  147       if (need <= vram) {
  148          char over[25]; /* overwrite comments with original resolutions */
  149          int bppx;      /* bytesperpixel multiplier */
  150          for (i = 0; i < vidtbllen; ++i) {
  151             vident = &vidtbl[i];
  152             if (vident->dotmode%100 == 28 && vident->colors >= 256
  153                && (info->xdots > vident->xdots || info->ydots > vident->ydots)
  154                && vram >= (unsigned long)
  155                   (info->xdots < vident->xdots ? vident->xdots : info->xdots)
  156                   * (info->ydots < vident->ydots ? vident->ydots : info->ydots)
  157                   * ((bppx = vident->dotmode/1000) < 2 ? ++bppx : bppx)) {
  158 
  159                sprintf(over,"<-VIRTUAL! at %4u x %4u",vident->xdots,vident->ydots);
  160                far_strcpy((char far *)vident->comment,(char far *)over);
  161 
  162                if (info->xdots > vident->xdots)
  163                   vident->xdots = info->xdots;
  164                if (info->ydots > vident->ydots)
  165                   vident->ydots = info->ydots;
  166              }  /* change entry to force VESA virtual scanline setup */
  167          }
  168       }
  169    }
  170 
  171    /* try to find exact match for vid mode */
  172    for (i = 0; i < vidtbllen; ++i) {
  173       vident = &vidtbl[i];
  174       if (info->xdots == vident->xdots && info->ydots == vident->ydots
  175         && filecolors == vident->colors
  176         && info->videomodeax == vident->videomodeax
  177         && info->videomodebx == vident->videomodebx
  178         && info->videomodecx == vident->videomodecx
  179         && info->videomodedx == vident->videomodedx
  180         && info->dotmode%100 == vident->dotmode%100) {
  181          initmode = i;
  182          break;
  183          }
  184       }
  185 
  186    /* exit in makepar mode if no exact match of video mode in file */
  187    if(*s_makepar == '\0' && initmode == -1)
  188       return(0);
  189 
  190    if (initmode == -1) /* try to find very good match for vid mode */
  191       for (i = 0; i < vidtbllen; ++i) {
  192          vident = &vidtbl[i];
  193          if (info->xdots == vident->xdots && info->ydots == vident->ydots
  194            && filecolors == vident->colors) {
  195             initmode = i;
  196             break;
  197             }
  198          }
  199 
  200    /* setup table entry for each vid mode, flagged for how well it matches */
  201    for (i = 0; i < vidtbllen; ++i) {
  202       far_memcpy((char far *)&videoentry,(char far *)&vidtbl[i],
  203                  sizeof(videoentry));
  204       tmpflags = VI_EXACT;
  205       if (videoentry.keynum == 0)
  206          tmpflags |= VI_NOKEY;
  207       if (info->xdots > videoentry.xdots || info->ydots > videoentry.ydots)
  208          tmpflags |= VI_SSMALL;
  209       else if (info->xdots < videoentry.xdots || info->ydots < videoentry.ydots)
  210          tmpflags |= VI_SBIG;
  211       if (filexdots > videoentry.xdots || fileydots > videoentry.ydots)
  212          tmpflags |= VI_VSMALL;
  213       else if (filexdots < videoentry.xdots || fileydots < videoentry.ydots)
  214          tmpflags |= VI_VBIG;
  215       if (filecolors > videoentry.colors)
  216          tmpflags |= VI_CSMALL;
  217       if (filecolors < videoentry.colors)
  218          tmpflags |= VI_CBIG;
  219       if (i == initmode)
  220          tmpflags -= VI_EXACT;
  221       if (videoentry.dotmode%100 == 11) {
  222          tmpflags |= VI_DISK2;
  223          if ((tmpflags & (VI_SBIG+VI_SSMALL+VI_VBIG+VI_VSMALL)) != 0)
  224             tmpflags |= VI_DISK1;
  225          }
  226       if (fileaspectratio != 0 && videoentry.dotmode%100 != 11
  227         && (tmpflags & VI_VSMALL) == 0) {
  228          ftemp = vid_aspect(filexdots,fileydots);
  229          if ( ftemp < fileaspectratio * 0.98
  230            || ftemp > fileaspectratio * 1.02)
  231             tmpflags |= VI_ASPECT;
  232          }
  233       vid[i].entnum = i;
  234       vid[i].flags  = tmpflags;
  235       }
  236 
  237 if (fastrestore  && !askvideo)
  238    initmode = adapter;
  239 
  240 #ifndef XFRACT
  241    gotrealmode = 0;
  242    if ((initmode < 0 || (askvideo && !initbatch)) && *s_makepar != '\0') {
  243       /* no exact match or (askvideo=yes and batch=no), and not
  244         in makepar mode, talk to user */
  245 
  246       qsort(vid,vidtbllen,sizeof(vid[0]),vidcompare); /* sort modes */
  247 
  248       attributes = (int *)&dstack[1000];
  249       for (i = 0; i < vidtbllen; ++i)
  250          attributes[i] = 1;
  251       vidptr = &vid[0]; /* for format_item */
  252 
  253       /* format heading */
  254       if (info->info_id[0] == 'G')
  255          strcpy(temp1,"      Non-fractal GIF");
  256       else {
  257          nameptr = curfractalspecific->name;
  258          if (*nameptr == '*') ++nameptr;
  259           if (display3d) nameptr = "3D Transform";
  260          if ((!strcmp(nameptr,"formula")) ||
  261              (!strcmp(nameptr,"lsystem")) ||
  262              (!strncmp(nameptr,"ifs",3))) /* for ifs and ifs3d */
  263                sprintf(temp1,"Type: %s -> %s",nameptr,blk_3_info->form_name);
  264          else
  265            sprintf(temp1,"Type: %s",nameptr);
  266          }
  267       sprintf((char *)dstack,"File: %-44s  %d x %d x %d\n%-52s",
  268              readname,filexdots,fileydots,filecolors,temp1);
  269       if (info->info_id[0] != 'G') {
  270          if (save_system)
  271             strcat((char *)dstack,"WinFract ");
  272          sprintf(temp1,"v%d.%01d",save_release/100,(save_release%100)/10);
  273          if (save_release%100) {
  274             i = strlen(temp1);
  275             temp1[i] = (char)((save_release%10) + '0');
  276             temp1[i+1] = 0;
  277             }
  278          if (save_system == 0 && save_release <= 1410)
  279             strcat(temp1," or earlier");
  280          strcat((char *)dstack,temp1);
  281          }
  282       strcat((char *)dstack,"\n");
  283       if (info->info_id[0] != 'G' && save_system == 0)
  284          if (initmode < 0)
  285             strcat((char *)dstack,"Saved in unknown video mode.");
  286          else {
  287             format_vid_inf(initmode,"",temp1);
  288             strcat((char *)dstack,temp1);
  289             }
  290       if (fileaspectratio != 0 && fileaspectratio != screenaspect)
  291          far_strcat((char *)dstack,warning);
  292       strcat((char *)dstack,"\n");
  293       /* set up instructions */
  294       far_strcpy(temp1,select_msg);
  295       if (info->info_id[0] != 'G')
  296          strcat(temp1,"TAB for fractal information, ");
  297       strcat(temp1,"ESCAPE to back out.");
  298 
  299       oldhelpmode = helpmode;
  300       helpmode = HELPLOADFILE;
  301       i = fullscreen_choice(0,(char *)dstack,hdg2,temp1,vidtbllen,NULL,attributes,
  302                              1,13,78,0,format_item,NULL,NULL,check_modekey);
  303       helpmode = oldhelpmode;
  304       if (i == -1)
  305          return(-1);
  306       if (i < 0) { /* returned -100 - videotable entry number */
  307          initmode = -100 - i;
  308          gotrealmode = 1;
  309          }
  310       else
  311          initmode = vid[i].entnum;
  312       }
313 #else 314 initmode = 0; 315 j = vidtbl[0].keynum; 316 gotrealmode = 0;
317 #endif 318 319 if (gotrealmode == 0) { /* translate from temp table to permanent */ 320 if ((j = vidtbl[i=initmode].keynum) != 0) { 321 for (initmode = 0; initmode < MAXVIDEOTABLE-1; ++initmode) 322 if (videotable[initmode].keynum == j) break; 323 if (initmode >= MAXVIDEOTABLE-1) j = 0; 324 } 325 if (j == 0) /* mode has no key, add to reserved slot at end */ 326 far_memcpy((char far *)&videotable[initmode=MAXVIDEOTABLE-1], 327 (char far *)&vidtbl[i],sizeof(*vidtbl)); 328 } 329 330 /* ok, we're going to return with a video mode */ 331 332 far_memcpy((char far *)&videoentry,(char far *)&videotable[initmode], 333 sizeof(videoentry)); 334 335 336 if (viewwindow && 337 filexdots == videoentry.xdots && fileydots == videoentry.ydots) { 338 /* pull image into a view window */ 339 if (calc_status != 4) /* if not complete */ 340 calc_status = 0; /* can't resume anyway */ 341 if (viewxdots) { 342 viewreduction = videoentry.xdots / viewxdots; 343 viewxdots = viewydots = 0; /* easier to use auto reduction */ 344 } 345 viewreduction = (float)((int)(viewreduction + 0.5)); /* need integer value */ 346 skipxdots = skipydots = (short)(viewreduction - 1); 347 return(0); 348 } 349 350 skipxdots = skipydots = 0; /* set for no reduction */ 351 if (videoentry.xdots < filexdots || videoentry.ydots < fileydots) { 352 /* set up to load only every nth pixel to make image fit */ 353 if (calc_status != 4) /* if not complete */ 354 calc_status = 0; /* can't resume anyway */ 355 skipxdots = skipydots = 1; 356 while (skipxdots * videoentry.xdots < filexdots) ++skipxdots; 357 while (skipydots * videoentry.ydots < fileydots) ++skipydots; 358 i = j = 0; 359 for(;;) { 360 tmpxdots = (filexdots + skipxdots - 1) / skipxdots; 361 tmpydots = (fileydots + skipydots - 1) / skipydots; 362 if (fileaspectratio == 0 || videoentry.dotmode%100 == 11) 363 break; 364 /* reduce further if that improves aspect */ 365 if ((ftemp = vid_aspect(tmpxdots,tmpydots)) > fileaspectratio) { 366 if (j) break; /* already reduced x, don't reduce y */ 367 ftemp2 = vid_aspect(tmpxdots,(fileydots+skipydots)/(skipydots+1)); 368 if (ftemp2 < fileaspectratio 369 && ftemp/fileaspectratio *0.9 <= fileaspectratio/ftemp2) 370 break; /* further y reduction is worse */ 371 ++skipydots; 372 ++i; 373 } 374 else { 375 if (i) break; /* already reduced y, don't reduce x */ 376 ftemp2 = vid_aspect((filexdots+skipxdots)/(skipxdots+1),tmpydots); 377 if (ftemp2 > fileaspectratio 378 && fileaspectratio/ftemp *0.9 <= ftemp2/fileaspectratio) 379 break; /* further x reduction is worse */ 380 ++skipxdots; 381 ++j; 382 } 383 } 384 filexdots = tmpxdots; 385 fileydots = tmpydots; 386 --skipxdots; 387 --skipydots; 388 } 389 390 if ((finalaspectratio = fileaspectratio) == 0) /* assume display correct */ 391 finalaspectratio = (float)vid_aspect(filexdots,fileydots); 392 if (finalaspectratio >= screenaspect-0.02 393 && finalaspectratio <= screenaspect+0.02) 394 finalaspectratio = screenaspect; 395 i = (int)(finalaspectratio * 1000.0 + 0.5); 396 finalaspectratio = (float)(i/1000.0); /* chop precision to 3 decimals */ 397 398 /* setup view window stuff */ 399 viewwindow = viewxdots = viewydots = 0; 400 if (filexdots != videoentry.xdots || fileydots != videoentry.ydots) { 401 /* image not exactly same size as screen */ 402 viewwindow = 1; 403 ftemp = finalaspectratio 404 * (double)videoentry.ydots / (double)videoentry.xdots 405 / screenaspect; 406 if (finalaspectratio <= screenaspect) { 407 i = (int)((double)videoentry.xdots / (double)filexdots * 20.0 + 0.5); 408 tmpreduce = (float)(i/20.0); /* chop precision to nearest .05 */ 409 i = (int)((double)videoentry.xdots / tmpreduce + 0.5); 410 j = (int)((double)i * ftemp + 0.5); 411 } 412 else { 413 i = (int)((double)videoentry.ydots / (double)fileydots * 20.0 + 0.5); 414 tmpreduce = (float)(i/20.0); /* chop precision to nearest .05 */ 415 j = (int)((double)videoentry.ydots / tmpreduce + 0.5); 416 i = (int)((double)j / ftemp + 0.5); 417 } 418 if (i != filexdots || j != fileydots) { /* too bad, must be explicit */ 419 viewxdots = filexdots; 420 viewydots = fileydots; 421 } 422 else 423 viewreduction = tmpreduce; /* ok, this works */ 424 } 425 if (*s_makepar && !fastrestore && !initbatch && 426 (fabs(finalaspectratio - screenaspect) > .00001 || viewxdots != 0)) { 427 static FCODE msg[] = {"\ 428 Warning: <V>iew parameters are being set to non-standard values.\n\ 429 Remember to reset them when finished with this image!"}; 430 stopmsg(4,msg); 431 } 432 return(0); 433 } 434 435 #ifndef XFRACT 436 static void format_item(int choice,char *buf) 437 { 438 char errbuf[10]; 439 unsigned tmpflags; 440 errbuf[0] = 0; 441 tmpflags = vidptr[choice].flags; 442 if (tmpflags & (VI_VSMALL+VI_CSMALL+VI_ASPECT)) strcat(errbuf,"*"); 443 if (tmpflags & VI_VSMALL) strcat(errbuf,"R"); 444 if (tmpflags & VI_CSMALL) strcat(errbuf,"C"); 445 if (tmpflags & VI_ASPECT) strcat(errbuf,"A"); 446 if (tmpflags & VI_VBIG) strcat(errbuf,"v"); 447 if (tmpflags & VI_CBIG) strcat(errbuf,"c"); 448 format_vid_inf(vidptr[choice].entnum,errbuf,buf); 449 } 450 451 static int check_modekey(int curkey,int choice) 452 { 453 int i; 454 i=choice; /* avoid warning */ 455 return (((i = check_vidmode_key(0,curkey)) >= 0) ? -100-i : 0); 456 } 457 #endif 458