1 /*
2         FRACTINT - The Ultimate Fractal Generator
3                         Main Routine
4 */
5 
6 #include <string.h>
7 #include <time.h>
8 #include <signal.h>
9 
10 #ifndef XFRACT
11 #include <io.h>
12 #endif
13 
14 #ifndef USE_VARARGS
15 #include <stdarg.h>
16 #else
17 #include <varargs.h>
18 #endif
19 
20 #include <ctype.h>
21 
22   /* #include hierarchy for fractint is a follows:
23         Each module should include port.h as the first fractint specific
24             include. port.h includes <stdlib.h>, <stdio.h>, <math.h>,
25             <float.h>; and, ifndef XFRACT, <dos.h>.
26         Most modules should include prototyp.h, which incorporates by
27             direct or indirect reference the following header files:
28                 mpmath.h
29                 cmplx.h
30                 fractint.h
31                 big.h
32                 biginit.h
33                 helpcom.h
34                 externs.h
35         Other modules may need the following, which must be included
36             separately:
37                 fractype.h
38                 helpdefs.h
39                 lsys.y
40                 targa.h
41                 targa_lc.h
42                 tplus.h
43         If included separately from prototyp.h, big.h includes cmplx.h
44            and biginit.h; and mpmath.h includes cmplx.h
45    */
46 
47 #include "port.h"
48 #include "prototyp.h"
49 #include "fractype.h"
50 #include "helpdefs.h"
51 
52 struct videoinfo videoentry;
53 int helpmode;
54 
55 long timer_start,timer_interval;        /* timer(...) start & total */
56 int     adapter;                /* Video Adapter chosen from list in ...h */
57 char *fract_dir1="", *fract_dir2="";
58 
59 #ifdef __TURBOC__
60 
61 /* yes, I *know* it's supposed to be compatible with Microsoft C,
62    but some of the routines need to know if the "C" code
63    has been compiled with Turbo-C.  This flag is a 1 if FRACTINT.C
64    (and presumably the other routines as well) has been compiled
65    with Turbo-C. */
66 int compiled_by_turboc = 1;
67 
68 /* set size to be used for overlays, a bit bigger than largest (help) */
69 unsigned _ovrbuffer = 54 * 64; /* that's 54k for overlays, counted in paragraphs */
70 
71 #else
72 
73 int compiled_by_turboc = 0;
74 
75 #endif
76 
77 /*
78    the following variables are out here only so
79    that the calcfract() and assembler routines can get at them easily
80 */
81         int     active_system = 0;      /* 0 for DOS, WINFRAC for Windows */
82         int     dotmode;                /* video access method      */
83         int     textsafe2;              /* textsafe override from videotable */
84         int     oktoprint;              /* 0 if printf() won't work */
85         int     sxdots,sydots;          /* # of dots on the physical screen    */
86         int     sxoffs,syoffs;          /* physical top left of logical screen */
87         int     xdots, ydots;           /* # of dots on the logical screen     */
88         double  dxsize, dysize;         /* xdots-1, ydots-1         */
89         int     colors = 256;           /* maximum colors available */
90         long    maxit;                  /* try this many iterations */
91         int     boxcount;               /* 0 if no zoom-box yet     */
92         int     zrotate;                /* zoombox rotation         */
93         double  zbx,zby;                /* topleft of zoombox       */
94         double  zwidth,zdepth,zskew;    /* zoombox size & shape     */
95 
96         int     fractype;               /* if == 0, use Mandelbrot  */
97         char    stdcalcmode;            /* '1', '2', 'g', 'b'       */
98         long    creal, cimag;           /* real, imag'ry parts of C */
99         long    delx, dely;             /* screen pixel increments  */
100         long    delx2, dely2;           /* screen pixel increments  */
101         LDBL    delxx, delyy;           /* screen pixel increments  */
102         LDBL    delxx2, delyy2;         /* screen pixel increments  */
103         long    delmin;                 /* for calcfrac/calcmand    */
104         double  ddelmin;                /* same as a double         */
105         double  param[MAXPARAMS];       /* parameters               */
106         double  potparam[3];            /* three potential parameters*/
107         long    fudge;                  /* 2**fudgefactor           */
108         long    l_at_rad;               /* finite attractor radius  */
109         double  f_at_rad;               /* finite attractor radius  */
110         int     bitshift;               /* fudgefactor              */
111 
112         int     badconfig = 0;          /* 'fractint.cfg' ok?       */
113         int     diskisactive;           /* disk-video drivers flag  */
114         int     diskvideo;              /* disk-video access flag   */
115         int hasinverse = 0;
116         /* note that integer grid is set when integerfractal && !invert;    */
117         /* otherwise the floating point grid is set; never both at once     */
118         long    far *lx0, far *ly0;     /* x, y grid                */
119         long    far *lx1, far *ly1;     /* adjustment for rotate    */
120         /* note that lx1 & ly1 values can overflow into sign bit; since     */
121         /* they're used only to add to lx0/ly0, 2s comp straightens it out  */
122         double far *dx0, far *dy0;      /* floating pt equivs */
123         double far *dx1, far *dy1;
124         int     integerfractal;         /* TRUE if fractal uses integer math */
125 
126         /* usr_xxx is what the user wants, vs what we may be forced to do */
127         char    usr_stdcalcmode;
128         int     usr_periodicitycheck;
129         long    usr_distest;
130         char    usr_floatflag;
131 
132         int     viewwindow;             /* 0 for full screen, 1 for window */
133         float   viewreduction;          /* window auto-sizing */
134         int     viewcrop;               /* nonzero to crop default coords */
135         float   finalaspectratio;       /* for view shape and rotation */
136         int     viewxdots,viewydots;    /* explicit view sizing */
137         int     video_cutboth;          /* nonzero to keep virtual aspect */
138         int     zscroll;                /* screen/zoombox 0 fixed, 1 relaxed */
139 
140 /*      HISTORY  far *history = NULL; */
141         U16 history = 0;
142         int maxhistory = 10;
143 
144 /* variables defined by the command line/files processor */
145 int     comparegif=0;                   /* compare two gif files flag */
146 int     timedsave=0;                    /* when doing a timed save */
147 int     resave_flag=0;                  /* tells encoder not to incr filename */
148 int     started_resaves=0;              /* but incr on first resave */
149 int     save_system;                    /* from and for save files */
150 int     tabmode = 1;                    /* tab display enabled */
151 
152 /* for historical reasons (before rotation):         */
153 /*    top    left  corner of screen is (xxmin,yymax) */
154 /*    bottom left  corner of screen is (xx3rd,yy3rd) */
155 /*    bottom right corner of screen is (xxmax,yymin) */
156 double  xxmin,xxmax,yymin,yymax,xx3rd,yy3rd; /* selected screen corners  */
157 long    xmin, xmax, ymin, ymax, x3rd, y3rd;  /* integer equivs           */
158 double  sxmin,sxmax,symin,symax,sx3rd,sy3rd; /* displayed screen corners */
159 double  plotmx1,plotmx2,plotmy1,plotmy2;     /* real->screen multipliers */
160 
161 int calc_status = -1; /* -1 no fractal                   */
162                       /*  0 parms changed, recalc reqd   */
163                       /*  1 actively calculating         */
164                       /*  2 interrupted, resumable       */
165                       /*  3 interrupted, not resumable   */
166                       /*  4 completed                    */
167 long calctime;
168 
169 int max_colors;                         /* maximum palette size */
170 int        zoomoff;                     /* = 0 when zoom is disabled    */
171 int        savedac;                     /* save-the-Video DAC flag      */
172 int browsing;                 /* browse mode flag */
173 char file_name_stack[16][MAX_NAME]; /* array of file names used while browsing */
174 int name_stack_ptr ;
175 double toosmall;
176 int  minbox;
177 int no_sub_images;
178 int autobrowse,doublecaution;
179 char brwscheckparms,brwschecktype;
180 char browsemask[MAX_NAME];
181 int scale_map[12] = {1,2,3,4,5,6,7,8,9,10,11,12}; /*RB, array for mapping notes to a (user defined) scale */
182 
183 
184 #define RESTART           1
185 #define IMAGESTART        2
186 #define RESTORESTART      3
187 #define CONTINUE          4
188 
check_samename(void)189 static void check_samename(void)
190    {
191       char drive[FILE_MAX_DRIVE];
192       char dir[FILE_MAX_DIR];
193       char fname[FILE_MAX_FNAME];
194       char ext[FILE_MAX_EXT];
195       char path[FILE_MAX_PATH];
196       splitpath(savename,drive,dir,fname,ext);
197       if(strcmp(fname,"fract001"))
198       {
199          makepath(path,drive,dir,fname,"gif");
200          if(access(path,0)==0)
201          exit(0);
202       }
203    }
204 
205 /* Do nothing if math error */
my_floating_point_err(int sig)206 static void my_floating_point_err(int sig)
207 {
208    if(sig != 0)
209       overflow = 1;
210 }
211 
212 #ifdef XFRACT
213 int
214 #else
215 void
216 #endif
main(int argc,char ** argv)217 main(int argc, char **argv)
218 {
219    int     resumeflag;
220    int     kbdchar;                     /* keyboard key-hit value       */
221    int     kbdmore;                     /* continuation variable        */
222    char stacked=0;                      /* flag to indicate screen stacked */
223 
224    /* this traps non-math library floating point errors */
225    signal( SIGFPE, my_floating_point_err );
226 
227    initasmvars();                       /* initialize ASM stuff */
228    InitMemory();
229    checkfreemem(0);
230    load_videotable(1); /* load fractint.cfg, no message yet if bad */
231    init_help();
232 
233 restart:   /* insert key re-starts here */
234    autobrowse     = FALSE;
235    brwschecktype  = TRUE;
236    brwscheckparms = TRUE;
237    doublecaution  = TRUE;
238    no_sub_images = FALSE;
239    toosmall = 6;
240    minbox   = 3;
241    strcpy(browsemask,"*.gif");
242    strcpy(browsename,"            ");
243    name_stack_ptr= -1; /* init loaded files stack */
244 
245    evolving = FALSE;
246    paramrangex = 4;
247    opx = newopx = -2.0;
248    paramrangey = 3;
249    opy = newopy = -1.5;
250    odpx = odpy = 0;
251    gridsz = 9;
252    fiddlefactor = 1;
253    fiddle_reduction = 1.0;
254    this_gen_rseed = (unsigned int)clock_ticks();
255    srand(this_gen_rseed);
256    initgene(); /*initialise pointers to lots of fractint variables for the evolution engine*/
257    start_showorbit = 0;
258    showdot = -1; /* turn off showdot if entered with <g> command */
259    calc_status = -1;                    /* no active fractal image */
260 
261    fract_dir1 = getenv("FRACTDIR");
262    if (fract_dir1==NULL) {
263        fract_dir1 = ".";
264    }
265 #ifdef SRCDIR
266    fract_dir2 = SRCDIR;
267 #else
268    fract_dir2 = ".";
269 #endif
270 
271    cmdfiles(argc,argv);         /* process the command-line */
272 #ifdef XFRACT
273    UnixInit();
274 #endif
275    dopause(0);                  /* pause for error msg if not batch */
276    init_msg(0,"",NULL,0);  /* this causes getakey if init_msg called on runup */
277    checkfreemem(1);
278    if(debugflag==450 && initbatch==1)   /* abort if savename already exists */
279        check_samename();
280 #ifdef XFRACT
281    initUnixWindow();
282 #endif
283    memcpy(olddacbox,dacbox,256*3);      /* save in case colors= present */
284 
285    if (debugflag == 8088)                cpu =  86; /* for testing purposes */
286    if (debugflag == 2870 && fpu >= 287 ) {
287       fpu = 287; /* for testing purposes */
288       cpu = 286;
289    }
290    if (debugflag ==  870 && fpu >=  87 ) {
291       fpu =  87; /* for testing purposes */
292       cpu =  86;
293    }
294    if (debugflag ==   70)                fpu =   0; /* for testing purposes */
295    if (getenv("NO87")) fpu = 0;
296 
297    if (fpu >= 287 && debugflag != 72)   /* Fast 287 math */
298       setup287code();
299    adapter_detect();                    /* check what video is really present */
300    if (debugflag >= 9002 && debugflag <= 9100) /* for testing purposes */
301       if (video_type > (debugflag-9000)/2)     /* adjust the video value */
302          video_type = (debugflag-9000)/2;
303 
304    diskisactive = 0;                    /* disk-video is inactive */
305    diskvideo = 0;                       /* disk driver is not in use */
306    setvideotext();                      /* switch to text mode */
307    savedac = 0;                         /* don't save the VGA DAC */
308 
309 #ifndef XFRACT
310    if (debugflag == 10000)              /* check for free memory */
311       showfreemem();
312 
313    if (badconfig < 0)                   /* fractint.cfg bad, no msg yet */
314       bad_fractint_cfg_msg();
315 #endif
316 
317    max_colors = 256;                    /* the Windows version is lower */
318    max_kbdcount=(cpu>=386) ? 80 : 30;   /* check the keyboard this often */
319 
320    if (showfile && initmode < 0) {
321       intro();                          /* display the credits screen */
322       if (keypressed() == ESC) {
323          getakey();
324 /* JPD : do not exit automatically under credits screen ...
325          goodbye();
326  */
327          }
328       }
329 
330    browsing = FALSE;
331 
332    if (!functionpreloaded)
333       set_if_old_bif();
334    stacked = 0;
335 restorestart:
336    if (colorpreloaded)
337       memcpy(dacbox,olddacbox,256*3);   /* restore in case colors= present */
338 
339    lookatmouse = 0;                     /* ignore mouse */
340 
341    while (showfile <= 0) {              /* image is to be loaded */
342       char *hdg;
343       tabmode = 0;
344       if (!browsing )     /*RB*/
345       {
346       if (overlay3d) {
347          hdg = "Select File for 3D Overlay";
348          helpmode = HELP3DOVLY;
349          }
350       else if (display3d) {
351          hdg = "Select File for 3D Transform";
352          helpmode = HELP3D;
353          }
354       else {
355          hdg = "Select File to Restore";
356          helpmode = HELPSAVEREST;
357          }
358       if (showfile < 0 && getafilename(hdg,gifmask,readname) < 0) {
359          showfile = 1;               /* cancelled */
360          initmode = -1;
361          break;
362          }
363 
364       name_stack_ptr = 0; /* 'r' reads first filename for browsing */
365       strcpy(file_name_stack[name_stack_ptr],browsename);
366       }
367 
368       evolving = viewwindow = 0;
369       showfile = 0;
370       helpmode = -1;
371       tabmode = 1;
372       if(stacked)
373       {
374          discardscreen();
375          setvideotext();
376          stacked = 0;
377       }
378       if (read_overlay() == 0)       /* read hdr, get video mode */
379          break;                      /* got it, exit */
380       if (browsing) /* break out of infinite loop, but lose your mind */
381          showfile = 1;
382       else
383          showfile = -1;                 /* retry */
384       }
385 
386    helpmode = HELPMENU;                 /* now use this help mode */
387    tabmode = 1;
388    lookatmouse = 0;                     /* ignore mouse */
389 
390    if (((overlay3d && !initbatch) || stacked) && initmode < 0) {        /* overlay command failed */
391       unstackscreen();                  /* restore the graphics screen */
392       stacked = 0;
393       overlay3d = 0;                    /* forget overlays */
394       display3d = 0;                    /* forget 3D */
395       if (calc_status ==3)
396          calc_status = 0;
397       resumeflag = 1;
398       goto resumeloop;                  /* ooh, this is ugly */
399       }
400 
401    savedac = 0;                         /* don't save the VGA DAC */
402 imagestart:                             /* calc/display a new image */
403    if(stacked)
404    {
405       discardscreen();
406       stacked = 0;
407    }
408 #ifdef XFRACT
409    usr_floatflag = 1;
410 #endif
411    got_status = -1;                     /* for tab_display */
412 
413    if (showfile)
414       if (calc_status > 0)              /* goto imagestart implies re-calc */
415          calc_status = 0;
416 
417    if (initbatch == 0)
418       lookatmouse = -PAGE_UP;           /* just mouse left button, == pgup */
419 
420    cyclelimit = initcyclelimit;         /* default cycle limit   */
421 
422    adapter = initmode;                  /* set the video adapter up */
423    initmode = -1;                       /* (once)                   */
424 
425    while (adapter < 0) {                /* cycle through instructions */
426       if (initbatch) {                          /* batch, nothing to do */
427          initbatch = 4;                 /* exit with error condition set */
428          goodbye();
429       }
430       kbdchar = main_menu(0);
431       if (kbdchar == INSERT) goto restart;      /* restart pgm on Insert Key */
432       if (kbdchar == DELETE)                    /* select video mode list */
433          kbdchar = select_video_mode(-1);
434       if ((adapter = check_vidmode_key(0,kbdchar)) >= 0)
435          break;                                 /* got a video mode now */
436 #ifndef XFRACT
437       if ('A' <= kbdchar && kbdchar <= 'Z')
438          kbdchar = tolower(kbdchar);
439 #endif
440 #ifndef XFRACT
441       if (kbdchar == 'd') {                     /* shell to DOS */
442          setclear();
443          printf("\n\nShelling to DOS - type 'exit' to return\n\n");
444          shell_to_dos();
445          goto imagestart;
446          }
447 #else
448       if (kbdchar == 'd') {                     /* redraw image in Xfractint */
449          initmode = adapter;
450          goto imagestart;
451          }
452 #endif
453 
454 #ifndef XFRACT
455       if (kbdchar == '@' || kbdchar == '2') {    /* execute commands */
456 #else
457       if (kbdchar == F2 || kbdchar == '@') {     /* We mapped @ to F2 */
458 #endif
459          if ((get_commands() & 4) == 0)
460             goto imagestart;
461          kbdchar = '3';                         /* 3d=y so fall thru '3' code */
462          }
463 #ifndef XFRACT
464       if (kbdchar == 'r' || kbdchar == '3' || kbdchar == '#') {
465 #else
466       if (kbdchar == 'r' || kbdchar == '3' || kbdchar == F3) {
467 #endif
468          display3d = 0;
469          if (kbdchar == '3' || kbdchar == '#' || kbdchar == F3)
470             display3d = 1;
471          if(colorpreloaded)
472             memcpy(olddacbox,dacbox,256*3);     /* save in case colors= present */
473          setvideotext(); /* switch to text mode */
474          showfile = -1;
475          goto restorestart;
476          }
477       if (kbdchar == 't') {                     /* set fractal type */
478          julibrot = 0;
479          get_fracttype();
480          goto imagestart;
481          }
482       if (kbdchar == 'x') {                     /* generic toggle switch */
483          get_toggles();
484          goto imagestart;
485          }
486       if (kbdchar == 'y') {                     /* generic toggle switch */
487          get_toggles2();
488          goto imagestart;
489          }
490       if (kbdchar == 'z') {                     /* type specific parms */
491          get_fract_params(1);
492          goto imagestart;
493          }
494       if (kbdchar == 'v') {                     /* view parameters */
495          get_view_params();
496          goto imagestart;
497          }
498       if (kbdchar == 2) {                       /* ctrl B = browse parms*/
499          get_browse_params();
500          goto imagestart;
501          }
502       if (kbdchar == 6) {                       /* ctrl f = sound parms*/
503          get_sound_params();
504          goto imagestart;
505          }
506       if (kbdchar == 'f') {                     /* floating pt toggle */
507          if (usr_floatflag == 0)
508             usr_floatflag = 1;
509          else
510             usr_floatflag = 0;
511          goto imagestart;
512          }
513       if (kbdchar == 'i') {                     /* set 3d fractal parms */
514          get_fract3d_params(); /* get the parameters */
515          goto imagestart;
516          }
517       if (kbdchar == 'g') {
518          get_cmd_string(); /* get command string */
519          goto imagestart;
520          }
521       /* buzzer(2); */                          /* unrecognized key */
522       }
523 
524    zoomoff = 1;                 /* zooming is enabled */
525    helpmode = HELPMAIN;         /* now use this help mode */
526    resumeflag = 0;  /* allows taking goto inside big_while_loop() */
527 resumeloop:
528    param_history(0); /* save old history */
529    /* this switch processes gotos that are now inside function */
530    switch(big_while_loop(&kbdmore,&stacked,resumeflag))
531    {
532    case RESTART:
533       goto restart;
534    case IMAGESTART:
535       goto imagestart;
536    case RESTORESTART:
537       goto restorestart;
538    default:
539       break;
540    }
541 #ifdef XFRACT
542    return(0);
543 #endif
544 }
545 
546 int check_key()
547 {
548    int key;
549    if((key = keypressed()) != 0) {
550       if (show_orbit)
551          scrub_orbit();
552       if(key != 'o' && key != 'O') {
553          fflush(stdout);
554          return(-1);
555       }
556       getakey();
557       if (dotmode != 11)
558          show_orbit = 1 - show_orbit;
559    }
560    return(0);
561 }
562 
563 /* timer function:
564      timer(0,(*fractal)())              fractal engine
565      timer(1,NULL,int width)            decoder
566      timer(2)                           encoder
567   */
568 #ifndef USE_VARARGS
569 int timer(int timertype,int(*subrtn)(),...)
570 #else
571 int timer(va_alist)
572 va_dcl
573 #endif
574 {
575    va_list arg_marker;  /* variable arg list */
576    char *timestring;
577    time_t ltime;
578    FILE *fp = NULL;
579    int out=0;
580    int i;
581    int do_bench;
582 
583 #ifndef USE_VARARGS
584    va_start(arg_marker,subrtn);
585 #else
586    int timertype;
587    int (*subrtn)();
588    va_start(arg_marker);
589    timertype = va_arg(arg_marker, int);
590    subrtn = (int (*)())va_arg(arg_marker, int *);
591 #endif
592 
593    do_bench = timerflag; /* record time? */
594    if (timertype == 2)   /* encoder, record time only if debug=200 */
595       do_bench = (debugflag == 200);
596    if(do_bench)
597       fp=dir_fopen(workdir,"bench","a");
598    timer_start = clock_ticks();
599    switch(timertype) {
600       case 0:
601          out = (*(int(*)(void))subrtn)();
602          break;
603       case 1:
604          i = va_arg(arg_marker,int);
605          out = (int)decoder((short)i); /* not indirect, safer with overlays */
606          break;
607       case 2:
608          out = encoder();            /* not indirect, safer with overlays */
609          break;
610       }
611    /* next assumes CLK_TCK is 10^n, n>=2 */
612    timer_interval = (clock_ticks() - timer_start) / (CLK_TCK/100);
613 
614    if(do_bench) {
615       time(&ltime);
616       timestring = ctime(&ltime);
617       timestring[24] = 0; /*clobber newline in time string */
618       switch(timertype) {
619          case 1:
620             fprintf(fp,"decode ");
621             break;
622          case 2:
623             fprintf(fp,"encode ");
624             break;
625          }
626       fprintf(fp,"%s type=%s resolution = %dx%d maxiter=%ld",
627           timestring,
628           curfractalspecific->name,
629           xdots,
630           ydots,
631           maxit);
632       fprintf(fp," time= %ld.%02ld secs\n",timer_interval/100,timer_interval%100);
633       if(fp != NULL)
634          fclose(fp);
635       }
636    return(out);
637 }
638