File: common\miscres.c
1 /*
2 Resident odds and ends that don't fit anywhere else.
3 */
4
5 #include <string.h>
6 #include <ctype.h>
7 #include <time.h>
8 #include <malloc.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 /*#ifdef __TURBOC__
21 #include <dir.h>
22 #endif */
23
24 /* see Fractint.c for a description of the "include" hierarchy */
25 #include "port.h"
26 #include "prototyp.h"
27 #include "fractype.h"
28 #include "helpdefs.h"
29
30 /* routines in this module */
31
32 static void trigdetails(char *);
33 static void area(void);
34
35 /* TW's static string consolidation campaign to help brain-dead compilers */
36 char s_cantwrite[] = {"Can't write %s"};
37 char s_cantcreate[] = {"Can't create %s"};
38 char s_cantunderstand[] = {"Can't understand %s"};
39 char s_cantfind[] = {"Can't find %s"};
40
41 #ifndef XFRACT
42
43 void findpath(char far *filename, char *fullpathname) /* return full pathnames */
44 {
45 char fname[FILE_MAX_FNAME];
46 char ext[FILE_MAX_EXT];
47 char temp_path[FILE_MAX_PATH];
48
49 splitpath(filename ,NULL,NULL,fname,ext);
50 makepath(temp_path,"" ,"" ,fname,ext);
51
52 if(checkcurdir != 0 && access(temp_path,0)==0) { /* file exists */
53 strcpy(fullpathname,temp_path);
54 return;
55 }
56
57 far_strcpy(temp_path,filename); /* avoid side effect changes to filename */
58
59 if (temp_path[0] == SLASHC || (temp_path[0] && temp_path[1] == ':')) {
60 if(access(temp_path,0)==0) { /* file exists */
61 strcpy(fullpathname,temp_path);
62 return;
63 }
64 else {
65 splitpath(temp_path ,NULL,NULL,fname,ext);
66 makepath(temp_path,"" ,"" ,fname,ext);
67 }
68 }
69 fullpathname[0] = 0; /* indicate none found */
70 /* #ifdef __TURBOC__ */ /* look for the file */
71 /* strcpy(fullpathname,searchpath(temp_path)); */
72 /* #else */
73 _searchenv(temp_path,"PATH",fullpathname);
74 /* #endif */
75 if (fullpathname[0] != 0) /* found it! */
76 if (strncmp(&fullpathname[2],SLASHSLASH,2) == 0) /* stupid klooge! */
77 strcpy(&fullpathname[3],temp_path);
78 }
79 #endif
80
81
82 void notdiskmsg()
83 {
84 static FCODE sorrymsg[]={
85 "This type may be slow using a real-disk based 'video' mode, but may not \n\
86 be too bad if you have enough expanded or extended memory. Press <Esc> to \n\
87 abort if it appears that your disk drive is working too hard."};
88 stopmsg(0,sorrymsg);
89 }
90
91 /* Wrapping version of putstring for long numbers */
92 /* row -- pointer to row variable, internally incremented if needed */
93 /* col1 -- starting column */
94 /* col2 -- last column */
95 /* color -- attribute (same as for putstring) */
96 /* maxrow -- max number of rows to write */
97 /* returns 0 if success, 1 if hit maxrow before done */
98 int putstringwrap(int *row,int col1,int col2,int color,char far *str,int maxrow)
99 {
100 char save1, save2;
101 int length, decpt, padding, startrow, done;
102 done = 0;
103 startrow = *row;
104 length = far_strlen(str);
105 padding = 3; /* space between col1 and decimal. */
106 /* find decimal point */
107 for(decpt=0;decpt < length; decpt++)
108 if(str[decpt] == '.')
109 break;
110 if(decpt >= length)
111 decpt = 0;
112 if(decpt < padding)
113 padding -= decpt;
114 else
115 padding = 0;
116 col1 += padding;
117 decpt += col1+1; /* column just past where decimal is */
118 while(length > 0)
119 {
120 if(col2-col1 < length)
121 {
122 if((*row - startrow + 1) >= maxrow)
123 done = 1;
124 else
125 done = 0;
126 save1 = str[col2-col1+1];
127 save2 = str[col2-col1+2];
128 if(done)
129 str[col2-col1+1] = '+';
130 else
131 str[col2-col1+1] = '\\';
132 str[col2-col1+2] = 0;
133 putstring(*row,col1,color,str);
134 if(done == 1)
135 break;
136 str[col2-col1+1] = save1;
137 str[col2-col1+2] = save2;
138 str += col2-col1;
139 (*row)++;
140 } else
141 putstring(*row,col1,color,str);
142 length -= col2-col1;
143 col1 = decpt; /* align with decimal */
144 }
145 return(done);
146 }
147
148 #define rad_to_deg(x) ((x)*(180.0/PI)) /* most people "think" in degrees */
149 #define deg_to_rad(x) ((x)*(PI/180.0))
150 /*
151 convert corners to center/mag
152 Rotation angles indicate how much the IMAGE has been rotated, not the
153 zoom box. Same goes for the Skew angles
154 */
155
156 #ifdef _MSC_VER
157 #pragma optimize( "", off )
158 #endif
159
160 void cvtcentermag(double *Xctr, double *Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
161 {
162 double Width, Height;
163 double a, b; /* bottom, left, diagonal */
164 double a2, b2, c2; /* squares of above */
165 double tmpx1, tmpx2, tmpy1, tmpy2, tmpa; /* temporary x, y, angle */
166
167 /* simple normal case first */
168 if (xx3rd == xxmin && yy3rd == yymin)
169 { /* no rotation or skewing, but stretching is allowed */
170 Width = xxmax - xxmin;
171 Height = yymax - yymin;
172 *Xctr = (xxmin + xxmax)/2.0;
173 *Yctr = (yymin + yymax)/2.0;
174 *Magnification = 2.0/Height;
175 *Xmagfactor = Height / (DEFAULTASPECT * Width);
176 *Rotation = 0.0;
177 *Skew = 0.0;
178 }
179 else
180 {
181 /* set up triangle ABC, having sides abc */
182 /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
183 tmpx1 = xxmax - xxmin;
184 tmpy1 = yymax - yymin;
185 c2 = tmpx1*tmpx1 + tmpy1*tmpy1;
186
187 tmpx1 = xxmax - xx3rd;
188 tmpy1 = yymin - yy3rd;
189 a2 = tmpx1*tmpx1 + tmpy1*tmpy1;
190 a = sqrt(a2);
191 *Rotation = -rad_to_deg(atan2( tmpy1, tmpx1 )); /* negative for image rotation */
192
193 tmpx2 = xxmin - xx3rd;
194 tmpy2 = yymax - yy3rd;
195 b2 = tmpx2*tmpx2 + tmpy2*tmpy2;
196 b = sqrt(b2);
197
198 tmpa = acos((a2+b2-c2)/(2*a*b)); /* save tmpa for later use */
199 *Skew = 90.0 - rad_to_deg(tmpa);
200
201 *Xctr = (xxmin + xxmax)*0.5;
202 *Yctr = (yymin + yymax)*0.5;
203
204 Height = b * sin(tmpa);
205
206 *Magnification = 2.0/Height; /* 1/(h/2) */
207 *Xmagfactor = Height / (DEFAULTASPECT * a);
208
209 /* if vector_a cross vector_b is negative */
210 /* then adjust for left-hand coordinate system */
211 if ( tmpx1*tmpy2 - tmpx2*tmpy1 < 0 && debugflag != 4010)
212 {
213 *Skew = -*Skew;
214 *Xmagfactor = -*Xmagfactor;
215 *Magnification = -*Magnification;
216 }
217 }
218 /* just to make par file look nicer */
219 if (*Magnification < 0)
220 {
221 *Magnification = -*Magnification;
222 *Rotation += 180;
223 }
224 #ifdef DEBUG
225 {
226 double txmin, txmax, tx3rd, tymin, tymax, ty3rd;
227 double error;
228 txmin = xxmin;
229 txmax = xxmax;
230 tx3rd = xx3rd;
231 tymin = yymin;
232 tymax = yymax;
233 ty3rd = yy3rd;
234 cvtcorners(*Xctr, *Yctr, *Magnification, *Xmagfactor, *Rotation, *Skew);
235 error = sqr(txmin - xxmin) +
236 sqr(txmax - xxmax) +
237 sqr(tx3rd - xx3rd) +
238 sqr(tymin - yymin) +
239 sqr(tymax - yymax) +
240 sqr(ty3rd - yy3rd);
241 if(error > .001)
242 showcornersdbl("cvtcentermag problem");
243 xxmin = txmin;
244 xxmax = txmax;
245 xx3rd = tx3rd;
246 yymin = tymin;
247 yymax = tymax;
248 yy3rd = ty3rd;
249 } 250 #endif
251 return;
252 }
253
254
255 /* convert center/mag to corners */
256 void cvtcorners(double Xctr, double Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
257 {
258 double x, y;
259 double h, w; /* half height, width */
260 double tanskew, sinrot, cosrot;
261
262 if (Xmagfactor == 0.0)
263 Xmagfactor = 1.0;
264
265 h = (double)(1/Magnification);
266 w = h / (DEFAULTASPECT * Xmagfactor);
267
268 if (Rotation == 0.0 && Skew == 0.0)
269 { /* simple, faster case */
270 xx3rd = xxmin = Xctr - w;
271 xxmax = Xctr + w;
272 yy3rd = yymin = Yctr - h;
273 yymax = Yctr + h;
274 return;
275 }
276
277 /* in unrotated, untranslated coordinate system */
278 tanskew = tan(deg_to_rad(Skew));
279 xxmin = -w + h*tanskew;
280 xxmax = w - h*tanskew;
281 xx3rd = -w - h*tanskew;
282 yymax = h;
283 yy3rd = yymin = -h;
284
285 /* rotate coord system and then translate it */
286 Rotation = deg_to_rad(Rotation);
287 sinrot = sin(Rotation);
288 cosrot = cos(Rotation);
289
290 /* top left */
291 x = xxmin * cosrot + yymax * sinrot;
292 y = -xxmin * sinrot + yymax * cosrot;
293 xxmin = x + Xctr;
294 yymax = y + Yctr;
295
296 /* bottom right */
297 x = xxmax * cosrot + yymin * sinrot;
298 y = -xxmax * sinrot + yymin * cosrot;
299 xxmax = x + Xctr;
300 yymin = y + Yctr;
301
302 /* bottom left */
303 x = xx3rd * cosrot + yy3rd * sinrot;
304 y = -xx3rd * sinrot + yy3rd * cosrot;
305 xx3rd = x + Xctr;
306 yy3rd = y + Yctr;
307
308 return;
309 }
310
311 /* convert corners to center/mag using bf */
312 void cvtcentermagbf(bf_t Xctr, bf_t Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
313 {
314 /* needs to be LDBL or won't work past 307 (-DBL_MIN_10_EXP) or so digits */
315 LDBL Width, Height;
316 LDBL a, b; /* bottom, left, diagonal */
317 LDBL a2, b2, c2; /* squares of above */
318 LDBL tmpx1, tmpx2, tmpy=0.0, tmpy1, tmpy2 ;
319 double tmpa; /* temporary x, y, angle */
320 bf_t bfWidth, bfHeight;
321 bf_t bftmpx, bftmpy;
322 int saved;
323 int signx;
324
325 saved = save_stack();
326
327 /* simple normal case first */
328 /* if (xx3rd == xxmin && yy3rd == yymin) */
329 if(!cmp_bf(bfx3rd, bfxmin) && !cmp_bf(bfy3rd, bfymin))
330 { /* no rotation or skewing, but stretching is allowed */
331 bfWidth = alloc_stack(bflength+2);
332 bfHeight = alloc_stack(bflength+2);
333 /* Width = xxmax - xxmin; */
334 sub_bf(bfWidth, bfxmax, bfxmin);
335 Width = bftofloat(bfWidth);
336 /* Height = yymax - yymin; */
337 sub_bf(bfHeight, bfymax, bfymin);
338 Height = bftofloat(bfHeight);
339 /* *Xctr = (xxmin + xxmax)/2; */
340 add_bf(Xctr, bfxmin, bfxmax);
341 half_a_bf(Xctr);
342 /* *Yctr = (yymin + yymax)/2; */
343 add_bf(Yctr, bfymin, bfymax);
344 half_a_bf(Yctr);
345 *Magnification = 2/Height;
346 *Xmagfactor = (double)(Height / (DEFAULTASPECT * Width));
347 *Rotation = 0.0;
348 *Skew = 0.0;
349 }
350 else
351 {
352 bftmpx = alloc_stack(bflength+2);
353 bftmpy = alloc_stack(bflength+2);
354
355 /* set up triangle ABC, having sides abc */
356 /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
357 /* IMPORTANT: convert from bf AFTER subtracting */
358
359 /* tmpx = xxmax - xxmin; */
360 sub_bf(bftmpx, bfxmax, bfxmin);
361 tmpx1 = bftofloat(bftmpx);
362 /* tmpy = yymax - yymin; */
363 sub_bf(bftmpy, bfymax, bfymin);
364 tmpy1 = bftofloat(bftmpy);
365 c2 = tmpx1*tmpx1 + tmpy1*tmpy1;
366
367 /* tmpx = xxmax - xx3rd; */
368 sub_bf(bftmpx, bfxmax, bfx3rd);
369 tmpx1 = bftofloat(bftmpx);
370
371 /* tmpy = yymin - yy3rd; */
372 sub_bf(bftmpy, bfymin, bfy3rd);
373 tmpy1 = bftofloat(bftmpy);
374 a2 = tmpx1*tmpx1 + tmpy1*tmpy1;
375 a = sqrtl(a2);
376
377 /* divide tmpx and tmpy by |tmpx| so that double version of atan2() can be used */
378 /* atan2() only depends on the ratio, this puts it in double's range */
379 signx = sign(tmpx1);
380 if(signx)
381 tmpy = tmpy1/tmpx1 * signx; /* tmpy = tmpy / |tmpx| */
382 *Rotation = (double)(-rad_to_deg(atan2( (double)tmpy, signx ))); /* negative for image rotation */
383
384 /* tmpx = xxmin - xx3rd; */
385 sub_bf(bftmpx, bfxmin, bfx3rd);
386 tmpx2 = bftofloat(bftmpx);
387 /* tmpy = yymax - yy3rd; */
388 sub_bf(bftmpy, bfymax, bfy3rd);
389 tmpy2 = bftofloat(bftmpy);
390 b2 = tmpx2*tmpx2 + tmpy2*tmpy2;
391 b = sqrtl(b2);
392
393 tmpa = acos((double)((a2+b2-c2)/(2*a*b))); /* save tmpa for later use */
394 *Skew = 90 - rad_to_deg(tmpa);
395
396 /* these are the only two variables that must use big precision */
397 /* *Xctr = (xxmin + xxmax)/2; */
398 add_bf(Xctr, bfxmin, bfxmax);
399 half_a_bf(Xctr);
400 /* *Yctr = (yymin + yymax)/2; */
401 add_bf(Yctr, bfymin, bfymax);
402 half_a_bf(Yctr);
403
404 Height = b * sin(tmpa);
405 *Magnification = 2/Height; /* 1/(h/2) */
406 *Xmagfactor = (double)(Height / (DEFAULTASPECT * a));
407
408 /* if vector_a cross vector_b is negative */
409 /* then adjust for left-hand coordinate system */
410 if ( tmpx1*tmpy2 - tmpx2*tmpy1 < 0 && debugflag != 4010)
411 {
412 *Skew = -*Skew;
413 *Xmagfactor = -*Xmagfactor;
414 *Magnification = -*Magnification;
415 }
416 }
417 if (*Magnification < 0)
418 {
419 *Magnification = -*Magnification;
420 *Rotation += 180;
421 }
422 restore_stack(saved);
423 return;
424 }
425
426
427 /* convert center/mag to corners using bf */
428 void cvtcornersbf(bf_t Xctr, bf_t Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
429 {
430 LDBL x, y;
431 LDBL h, w; /* half height, width */
432 LDBL xmin, ymin, xmax, ymax, x3rd, y3rd;
433 double tanskew, sinrot, cosrot;
434 bf_t bfh, bfw;
435 bf_t bftmp;
436 int saved;
437
438 saved = save_stack();
439 bfh = alloc_stack(bflength+2);
440 bfw = alloc_stack(bflength+2);
441
442 if (Xmagfactor == 0.0)
443 Xmagfactor = 1.0;
444
445 h = 1/Magnification;
446 floattobf(bfh, h);
447 w = h / (DEFAULTASPECT * Xmagfactor);
448 floattobf(bfw, w);
449
450 if (Rotation == 0.0 && Skew == 0.0)
451 { /* simple, faster case */
452 /* xx3rd = xxmin = Xctr - w; */
453 sub_bf(bfxmin, Xctr, bfw);
454 copy_bf(bfx3rd, bfxmin);
455 /* xxmax = Xctr + w; */
456 add_bf(bfxmax, Xctr, bfw);
457 /* yy3rd = yymin = Yctr - h; */
458 sub_bf(bfymin, Yctr, bfh);
459 copy_bf(bfy3rd, bfymin);
460 /* yymax = Yctr + h; */
461 add_bf(bfymax, Yctr, bfh);
462 restore_stack(saved);
463 return;
464 }
465
466 bftmp = alloc_stack(bflength+2);
467 /* in unrotated, untranslated coordinate system */
468 tanskew = tan(deg_to_rad(Skew));
469 xmin = -w + h*tanskew;
470 xmax = w - h*tanskew;
471 x3rd = -w - h*tanskew;
472 ymax = h;
473 y3rd = ymin = -h;
474
475 /* rotate coord system and then translate it */
476 Rotation = deg_to_rad(Rotation);
477 sinrot = sin(Rotation);
478 cosrot = cos(Rotation);
479
480 /* top left */
481 x = xmin * cosrot + ymax * sinrot;
482 y = -xmin * sinrot + ymax * cosrot;
483 /* xxmin = x + Xctr; */
484 floattobf(bftmp, x);
485 add_bf(bfxmin, bftmp, Xctr);
486 /* yymax = y + Yctr; */
487 floattobf(bftmp, y);
488 add_bf(bfymax, bftmp, Yctr);
489
490 /* bottom right */
491 x = xmax * cosrot + ymin * sinrot;
492 y = -xmax * sinrot + ymin * cosrot;
493 /* xxmax = x + Xctr; */
494 floattobf(bftmp, x);
495 add_bf(bfxmax, bftmp, Xctr);
496 /* yymin = y + Yctr; */
497 floattobf(bftmp, y);
498 add_bf(bfymin, bftmp, Yctr);
499
500 /* bottom left */
501 x = x3rd * cosrot + y3rd * sinrot;
502 y = -x3rd * sinrot + y3rd * cosrot;
503 /* xx3rd = x + Xctr; */
504 floattobf(bftmp, x);
505 add_bf(bfx3rd, bftmp, Xctr);
506 /* yy3rd = y + Yctr; */
507 floattobf(bftmp, y);
508 add_bf(bfy3rd, bftmp, Yctr);
509
510 restore_stack(saved);
511 return;
512 }
513
514 #ifdef _MSC_VER
515 #pragma optimize( "", on )
516 #endif
517
518 void updatesavename(char *filename) /* go to the next file name */
519 {
520 char *save, *hold;
521 char drive[FILE_MAX_DRIVE];
522 char dir[FILE_MAX_DIR];
523 char fname[FILE_MAX_FNAME];
524 char ext[FILE_MAX_EXT];
525
526 splitpath(filename ,drive,dir,fname,ext);
527
528 hold = fname + strlen(fname) - 1; /* start at the end */
529 while(hold >= fname && (*hold == ' ' || isdigit(*hold))) /* skip backwards */
530 hold--;
531 hold++; /* recover first digit */
532 while (*hold == '0') /* skip leading zeros */
533 hold++;
534 save = hold;
535 while (*save) { /* check for all nines */
536 if (*save != '9')
537 break;
538 save++;
539 }
540 if (!*save) /* if the whole thing is nines then back */
541 save = hold - 1; /* up one place. Note that this will eat */
542 /* your last letter if you go to far. */
543 else
544 save = hold;
545 sprintf(save,"%ld",atol(hold)+1); /* increment the number */
546 makepath(filename,drive,dir,fname,ext);
547 }
548
549 int check_writefile(char *name,char *ext)
550 {
551 /* after v16 release, change encoder.c to also use this routine */
552 char openfile[FILE_MAX_DIR];
553 char opentype[20];
554 /* int i; */
555 char *period;
556 nextname:
557 strcpy(openfile,name);
558 strcpy(opentype,ext);
559 #if 0
565 #endif
566 if((period = has_ext(openfile)) != NULL)
567 {
568 strcpy(opentype,period);
569 *period = 0;
570 }
571 strcat(openfile,opentype);
572 if (access(openfile,0) != 0) /* file doesn't exist */
573 {
574 strcpy(name,openfile);
575 return 0;
576 }
577 /* file already exists */
578 if (overwrite == 0) {
579 updatesavename(name);
580 goto nextname;
581 }
582 return 1;
583 }
584
585 /* ('check_key()' was moved to FRACTINT.C for MSC7-overlay speed purposes) */
586 /* ('timer()' was moved to FRACTINT.C for MSC7-overlay speed purposes) */
587
588 BYTE trigndx[] = {SIN,SQR,SINH,COSH};
589 #ifndef XFRACT
590 void (*ltrig0)(void) = lStkSin;
591 void (*ltrig1)(void) = lStkSqr;
592 void (*ltrig2)(void) = lStkSinh;
593 void (*ltrig3)(void) = lStkCosh;
594 void (*mtrig0)(void) = mStkSin;
595 void (*mtrig1)(void) = mStkSqr;
596 void (*mtrig2)(void) = mStkSinh;
597 void (*mtrig3)(void) = mStkCosh;
598 #endif
599 void (*dtrig0)(void) = dStkSin;
600 void (*dtrig1)(void) = dStkSqr;
601 void (*dtrig2)(void) = dStkSinh;
602 void (*dtrig3)(void) = dStkCosh;
603
604 /* struct trig_funct_lst trigfn[] was moved to prompts1.c */
605
606 void showtrig(char *buf) /* return display form of active trig functions */
607 {
608 char tmpbuf[30];
609 *buf = 0; /* null string if none */
610 trigdetails(tmpbuf);
611 if (tmpbuf[0])
612 sprintf(buf," function=%s",tmpbuf);
613 }
614
615 static void trigdetails(char *buf)
616 {
617 int i, numfn;
618 char tmpbuf[20];
619 if(fractype==JULIBROT || fractype==JULIBROTFP)
620 numfn = (fractalspecific[neworbittype].flags >> 6) & 7;
621 else
622 numfn = (curfractalspecific->flags >> 6) & 7;
623 if(curfractalspecific == &fractalspecific[FORMULA] ||
624 curfractalspecific == &fractalspecific[FFORMULA] )
625 numfn = maxfn;
626 *buf = 0; /* null string if none */
627 if (numfn>0) {
628 strcpy(buf,trigfn[trigndx[0]].name);
629 i = 0;
630 while(++i < numfn) {
631 sprintf(tmpbuf,"/%s",trigfn[trigndx[i]].name);
632 strcat(buf,tmpbuf);
633 }
634 }
635 }
636
637 /* set array of trig function indices according to "function=" command */
638 int set_trig_array(int k, char *name)
639 {
640 char trigname[10];
641 int i;
642 char *slash;
643 strncpy(trigname,name,6);
644 trigname[6] = 0; /* safety first */
645
646 if ((slash = strchr(trigname,'/')) != NULL)
647 *slash = 0;
648
649 strlwr(trigname);
650
651 for(i=0;i<numtrigfn;i++)
652 {
653 if(strcmp(trigname,trigfn[i].name)==0)
654 {
655 trigndx[k] = (BYTE)i;
656 set_trig_pointers(k);
657 break;
658 }
659 }
660 return(0);
661 }
662 void set_trig_pointers(int which)
663 {
664 /* set trig variable functions to avoid array lookup time */
665 int i;
666 switch(which)
667 {
668 case 0:
669 #ifndef XFRACT
670 ltrig0 = trigfn[trigndx[0]].lfunct;
671 mtrig0 = trigfn[trigndx[0]].mfunct;
672 #endif
673 dtrig0 = trigfn[trigndx[0]].dfunct;
674 break;
675 case 1:
676 #ifndef XFRACT
677 ltrig1 = trigfn[trigndx[1]].lfunct;
678 mtrig1 = trigfn[trigndx[1]].mfunct;
679 #endif
680 dtrig1 = trigfn[trigndx[1]].dfunct;
681 break;
682 case 2:
683 #ifndef XFRACT
684 ltrig2 = trigfn[trigndx[2]].lfunct;
685 mtrig2 = trigfn[trigndx[2]].mfunct;
686 #endif
687 dtrig2 = trigfn[trigndx[2]].dfunct;
688 break;
689 case 3:
690 #ifndef XFRACT
691 ltrig3 = trigfn[trigndx[3]].lfunct;
692 mtrig3 = trigfn[trigndx[3]].mfunct;
693 #endif
694 dtrig3 = trigfn[trigndx[3]].dfunct;
695 break;
696 default: /* do 'em all */
697 for(i=0;i<4;i++)
698 set_trig_pointers(i);
699 break;
700 }
701 }
702
703 static FCODE sfractal_type[] = {"Fractal type:"};
704 static FCODE sitem_name[] = {"Item name:"};
705 static FCODE sitem_file[] = {"Item file:"};
706 static FCODE s3D_transform[] = {"3D Transform"};
707 static FCODE syou_are_cycling[] = {"You are in color-cycling mode"};
708 static FCODE sfloating_point[] = {"Floating-point"};
709 static FCODE ssolid_guessing[] = {"Solid Guessing"};
710 static FCODE sboundary_tracing[] = {"Boundary Tracing"};
711 static FCODE stesseral[] = {"Tesseral"};
712 static FCODE sdiffusion[] = {"Diffusion"};
713 static FCODE sorbits[] = {"Orbits"};
714 static FCODE scalculation_time[] = {"Calculation time:"};
715 static FCODE siterations[] = {" 1000's of points:"};
716 static FCODE scornersxy[] = {"Corners: X Y"};
717 static FCODE stop_left[] = {"Top-l"};
718 static FCODE sbottom_right[] = {"Bot-r"};
719 static FCODE sbottom_left[] = {"Bot-l"};
720 static FCODE scenter[] = {"Ctr"};
721 static FCODE struncate[] = {"(Center values shown truncated to 320 decimals)"};
722 static FCODE smag[] = {"Mag"};
723 static FCODE sxmag[] = {"X-Mag-Factor"};
724 static FCODE srot[] = {"Rotation"};
725 static FCODE sskew[] = {"Skew"};
726 static FCODE sparams[] = {"Params "};
727 static FCODE siteration_maximum[] ={"Current (Max) Iteration: "};
728 static FCODE seffective_bailout[] ={" Effective bailout: "};
729 static FCODE scurrent_rseed[] = {"Current 'rseed': "};
730 static FCODE sinversion_radius[] = {"Inversion radius: "};
731 static FCODE sxcenter[] = {" xcenter: "};
732 static FCODE sycenter[] = {" ycenter: "};
733 static FCODE sparms_chgd[] = {"Parms chgd since generated"};
734 static FCODE sstill_being[] = {"Still being generated"};
735 static FCODE sinterrupted_resumable[] = {"Interrupted, resumable"};
736 static FCODE sinterrupted_non_resumable[] = {"Interrupted, non-resumable"};
737 static FCODE simage_completed[] = {"Image completed"};
738 static FCODE sflag_is_activated[] = {" flag is activated"};
739 static FCODE sinteger_math[] = {"Integer math is in use"};
740 static FCODE sin_use_required[] = {" in use (required)"};
741 static FCODE sarbitrary_precision[] = {"Arbitrary precision "};
742 #ifdef XFRACT
743 static FCODE spressanykey[] = {"Press any key to continue, F6 for area, F7 for next page"}; 744 #else
745 static FCODE spressanykey[] = {"Press any key to continue, F6 for area, CTRL-TAB for next page"};
746 #endif
747 static FCODE spressanykey1[] = {"Press Esc to continue, Backspace for first screen"};
748 static FCODE sbatch[] = {" (Batch mode)"};
749 static FCODE ssavename[] = {"Savename: "};
750 static FCODE sstopsecret[] = {"Top Secret Developer's Screen"};
751 static FCODE sthreepass[] = {" (threepass)"};
752 static FCODE sreallylongtime[] = {"A long time! (> 24.855 days)"};
753
754 void get_calculation_time(char *msg, long ctime)
755 {
756 if (ctime >= 0)
757 {
758 sprintf(msg,"%3ld:%02ld:%02ld.%02ld", ctime/360000L,
759 (ctime%360000L)/6000, (ctime%6000)/100, ctime%100);
760 }
761 else
762 far_strcpy(msg,sreallylongtime);
763 }
764
765 static void show_str_var(char *name, char *var, int *row, char *msg)
766 {
767 if(var == NULL)
768 return;
769 if(*var != 0)
770 {
771 sprintf(msg,"%s=%s",name,var);
772 putstring((*row)++,2,C_GENERAL_HI,msg);
773 }
774 }
775
776 int tab_display_2(char *msg)
777 {
778 extern long maxptr, maxstack, startstack;
779 int s_row,key,ret=0;
780 helptitle();
781 setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
782
783 s_row = 1;
784 putstringcenter(s_row++,0,80,C_PROMPT_HI, sstopsecret);
785 sprintf(msg,"Version %d patch %d",release, patchlevel);
786 putstring(++s_row,2,C_GENERAL_HI,msg);
787 sprintf(msg,"%lu bytes conventional stack free",stackavail());
788 putstring(++s_row,2,C_GENERAL_HI,msg);
789 sprintf(msg,"%ld of %ld bignum memory used",maxptr,maxstack);
790 putstring(++s_row,2,C_GENERAL_HI,msg);
791 sprintf(msg," %ld used for bignum globals", startstack);
792 putstring(++s_row,2,C_GENERAL_HI,msg);
793 sprintf(msg," %ld stack used == %ld variables of length %d",
794 maxptr-startstack,(long)((maxptr-startstack)/(rbflength+2)),rbflength+2);
795 putstring(++s_row,2,C_GENERAL_HI,msg);
796 if(bf_math)
797 {
798 sprintf(msg,"intlength %-d bflength %-d ",intlength, bflength);
799 putstring(++s_row,2,C_GENERAL_HI,msg);
800 }
801 s_row++;
802 show_str_var(s_tempdir, tempdir, &s_row, msg);
803 show_str_var(s_workdir, workdir, &s_row, msg);
804 show_str_var(s_printfile, PrintName, &s_row, msg);
805 show_str_var(s_filename, readname, &s_row, msg);
806 show_str_var(s_formulafile,FormFileName, &s_row, msg);
807 show_str_var(s_savename, savename, &s_row, msg);
808 show_str_var(s_parmfile, CommandFile, &s_row, msg);
809 show_str_var(s_ifsfile, IFSFileName, &s_row, msg);
810 show_str_var(s_autokeyname,autoname, &s_row, msg);
811 show_str_var(s_lightname, light_name, &s_row, msg);
812 show_str_var(s_map, MAP_name, &s_row, msg);
813 sprintf(msg,"Sizeof fractalspecific array %d",
814 num_fractal_types*(int)sizeof(struct fractalspecificstuff));
815 putstring(s_row++,2,C_GENERAL_HI,msg);
816 sprintf(msg,"calc_status %d pixel [%d,%d]",calc_status,col,row);
817 putstring(s_row++,2,C_GENERAL_HI,msg);
818 if(fractype==FORMULA || fractype==FFORMULA)
819 {
820 sprintf(msg,"total_formula_mem %ld Max_Ops (posp) %u Max_Args (vsp) %u Used_extra %u",
821 total_formula_mem,posp,vsp,used_extra);
822 putstring(s_row++,2,C_GENERAL_HI,msg);
823 sprintf(msg," Store ptr %d Loadptr %d Max_Ops var %u Max_Args var %u LastInitOp %d",
824 StoPtr,LodPtr,Max_Ops,Max_Args,LastInitOp);
825 putstring(s_row++,2,C_GENERAL_HI,msg);
826 }
827 else if(rhombus_stack[0])
828 {
829 sprintf(msg,"SOI Recursion %d stack free %d %d %d %d %d %d %d %d %d %d",
830 max_rhombus_depth+1,
831 rhombus_stack[0],
832 rhombus_stack[1],
833 rhombus_stack[2],
834 rhombus_stack[3],
835 rhombus_stack[4],
836 rhombus_stack[5],
837 rhombus_stack[6],
838 rhombus_stack[7],
839 rhombus_stack[8],
840 rhombus_stack[9]);
841 putstring(s_row++,2,C_GENERAL_HI,msg);
842 }
843
844 /*
845 sprintf(msg,"xdots %d ydots %d sxdots %d sydots %d",xdots,ydots,sxdots,sydots);
846 putstring(s_row++,2,C_GENERAL_HI,msg);
847 */
848 sprintf(msg,"xxstart %d xxstop %d yystart %d yystop %d %s uses_ismand %d",
849 xxstart,xxstop,yystart,yystop,
850 #ifndef XFRACT
851 curfractalspecific->orbitcalc == fFormula?"fast parser":
852 #endif
853 curfractalspecific->orbitcalc == Formula?"slow parser":
854 curfractalspecific->orbitcalc == BadFormula?"bad formula":
855 "",uses_ismand);
856 putstring(s_row++,2,C_GENERAL_HI,msg);
857 /*
858 sprintf(msg,"ixstart %d ixstop %d iystart %d iystop %d bitshift %d",
859 ixstart,ixstop,iystart,iystop,bitshift);
860 */
861 {
862 sprintf(msg,"minstackavail %d llimit2 %ld use_grid %d",
863 minstackavail,llimit2,use_grid);
864 }
865 putstring(s_row++,2,C_GENERAL_HI,msg);
866 putstringcenter(24,0,80,C_GENERAL_LO,spressanykey1);
867 *msg = 0;
868 again:
869 putstring(s_row,2,C_GENERAL_HI,msg);
870 key=getakeynohelp();
871 if(key != ESC && key != BACKSPACE && key != TAB)
872 {
873 sprintf(msg,"%d ",key);
874 goto again;
875 }
876 if(key == BACKSPACE || key == TAB)
877 ret = 1;
878 return(ret);
879 }
880
881 int tab_display() /* display the status of the current image */
882 {
883 int s_row, i, j, addrow=0;
884 double Xctr, Yctr;
885 LDBL Magnification;
886 double Xmagfactor, Rotation, Skew;
887 bf_t bfXctr=NULL, bfYctr=NULL;
888 char msg[350];
889 char far *msgptr;
890 int key;
891 int saved=0;
892 int dec;
893 int k;
894 U16 save_extra_handle = 0;
895 BYTE far *ptr_to_extraseg = NULL;
896 int hasformparam = 0;
897
898 if (calc_status < 0) { /* no active fractal image */
899 return(0); /* (no TAB on the credits screen) */
900 }
901 if (calc_status == 1) /* next assumes CLK_TCK is 10^n, n>=2 */
902 calctime += (clock_ticks() - timer_start) / (CLK_TCK/100);
903 stackscreen();
904 if(bf_math)
905 {
906 /* Save memory from the beginning of extraseg to ENDVID=22400 */
907 /* This is so the bf_math manipulations here don't corrupt */
908 /* the video modes or screen prompts. */
909 ptr_to_extraseg = MK_FP(extraseg,0);
910 save_extra_handle = MemoryAlloc((U16)22400, 1L, FARMEM);
911 MoveToMemory(ptr_to_extraseg,(U16)22400,1L,0L,save_extra_handle);
912 saved = save_stack();
913 bfXctr = alloc_stack(bflength+2);
914 bfYctr = alloc_stack(bflength+2);
915 }
916 if (fractype == FORMULA || fractype == FFORMULA)
917 for (i = 0; i < MAXPARAMS; i += 2)
918 if (!paramnotused(i))
919 hasformparam++;
920 top:
921 k = 0; /* initialize here so parameter line displays correctly on return
922 from control-tab */
923 helptitle();
924 setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
925 s_row = 2;
926 putstring(s_row,2,C_GENERAL_MED,sfractal_type);
927 if (display3d > 0)
928 putstring(s_row,16,C_GENERAL_HI,s3D_transform);
929 else {
930 putstring(s_row,16,C_GENERAL_HI,
931 curfractalspecific->name[0] == '*' ?
932 &curfractalspecific->name[1] :
933 curfractalspecific->name);
934 i = 0;
935 if (fractype == FORMULA || fractype == FFORMULA)
936 {
937 putstring(s_row+1,3,C_GENERAL_MED,sitem_name);
938 putstring(s_row+1,16,C_GENERAL_HI,FormName);
939 i = strlen(FormName)+1;
940 putstring(s_row+2,3,C_GENERAL_MED,sitem_file);
941 if((int)strlen(FormFileName) >= 29)
942 addrow = 1;
943 putstring(s_row+2+addrow,16,C_GENERAL_HI,FormFileName);
944 }
945 trigdetails(msg);
946 putstring(s_row+1,16+i,C_GENERAL_HI,msg);
947 if (fractype == LSYSTEM)
948 {
949 putstring(s_row+1,3,C_GENERAL_MED,sitem_name);
950 putstring(s_row+1,16,C_GENERAL_HI,LName);
951 putstring(s_row+2,3,C_GENERAL_MED,sitem_file);
952 if((int)strlen(LFileName) >= 28)
953 addrow = 1;
954 putstring(s_row+2+addrow,16,C_GENERAL_HI,LFileName);
955 }
956 if (fractype == IFS || fractype == IFS3D)
957 {
958 putstring(s_row+1,3,C_GENERAL_MED,sitem_name);
959 putstring(s_row+1,16,C_GENERAL_HI,IFSName);
960 putstring(s_row+2,3,C_GENERAL_MED,sitem_file);
961 if((int)strlen(IFSFileName) >= 28)
962 addrow = 1;
963 putstring(s_row+2+addrow,16,C_GENERAL_HI,IFSFileName);
964 }
965 }
966
967 switch (calc_status) {
968 case 0: msgptr = sparms_chgd;
969 break;
970 case 1: msgptr = sstill_being;
971 break;
972 case 2: msgptr = sinterrupted_resumable;
973 break;
974 case 3: msgptr = sinterrupted_non_resumable;
975 break;
976 case 4: msgptr = simage_completed;
977 break;
978 default: msgptr = "";
979 }
980 putstring(s_row,45,C_GENERAL_HI,msgptr);
981 if(initbatch && calc_status != 0)
982 putstring(-1,-1,C_GENERAL_HI,sbatch);
983
984 if (helpmode == HELPCYCLING)
985 putstring(s_row+1,45,C_GENERAL_HI,syou_are_cycling);
986 ++s_row;
987 /* if(bf_math == 0) */
988 ++s_row;
989
990 i = j = 0;
991 if (display3d > 0) {
992 if (usr_floatflag)
993 j = 1;
994 }
995 else
996 if (floatflag)
997 j = (usr_floatflag) ? 1 : 2;
998 if(bf_math==0)
999 {
1000 if (j) {
1001 putstring(s_row,45,C_GENERAL_HI,sfloating_point);
1002
1003 putstring(-1,-1,C_GENERAL_HI,(j == 1) ? sflag_is_activated
1004 : sin_use_required );
1005 i = 1;
1006 }
1007 else
1008 {
1009 putstring(s_row,45,C_GENERAL_HI,sinteger_math);
1010 i = 1;
1011 }
1012 } else
1013 {
1014 sprintf(msg,"(%-d decimals)",decimals /*getprecbf(CURRENTREZ)*/);
1015 putstring(s_row,45,C_GENERAL_HI,sarbitrary_precision);
1016 putstring(-1,-1,C_GENERAL_HI,msg);
1017
1018 i = 1;
1019 }
1020
1021 s_row += i;
1022
1023 if (calc_status == 1 || calc_status == 2)
1024 if (curfractalspecific->flags&NORESUME)
1025 {
1026 static FCODE msg[] = {"Note: can't resume this type after interrupts other than <tab> and <F1>"};
1027 putstring(s_row++,2,C_GENERAL_HI,msg);
1028 }
1029 s_row += addrow;
1030 putstring(s_row,2,C_GENERAL_MED,ssavename);
1031 putstring(s_row,-1,C_GENERAL_HI,savename);
1032
1033 /* if(bf_math == 0) */
1034 ++s_row;
1035
1036 if (got_status >= 0 && (calc_status == 1 || calc_status == 2)) {
1037 switch (got_status) {
1038 case 0:
1039 sprintf(msg,"%d Pass Mode",totpasses);
1040 putstring(s_row,2,C_GENERAL_HI,msg);
1041 if(usr_stdcalcmode=='3')
1042 putstring(s_row,-1,C_GENERAL_HI,sthreepass);
1043 break;
1044 case 1:
1045 putstring(s_row,2,C_GENERAL_HI,ssolid_guessing);
1046 if(usr_stdcalcmode=='3')
1047 putstring(s_row,-1,C_GENERAL_HI,sthreepass);
1048 break;
1049 case 2:
1050 putstring(s_row,2,C_GENERAL_HI,sboundary_tracing);
1051 break;
1052 case 3:
1053 sprintf(msg,"Processing row %d (of %d) of input image",currow,fileydots);
1054 putstring(s_row,2,C_GENERAL_HI,msg);
1055 break;
1056 case 4:
1057 putstring(s_row,2,C_GENERAL_HI,stesseral);
1058 break;
1059 case 5:
1060 putstring(s_row,2,C_GENERAL_HI,sdiffusion);
1061 break;
1062 case 6:
1063 putstring(s_row,2,C_GENERAL_HI,sorbits);
1064 break;
1065 }
1066 ++s_row;
1067 if (got_status == 5 ) {
1068 sprintf(msg,"%2.2f%% done, counter at %lu of %lu (%u bits)",
1069 (100.0 * dif_counter)/dif_limit,
1070 dif_counter,dif_limit,bits);
1071 putstring(s_row,2,C_GENERAL_MED,msg);
1072 ++s_row;
1073 } else
1074 if (got_status != 3) {
1075 sprintf(msg,"Working on block (y,x) [%d,%d]...[%d,%d], ",
1076 yystart,xxstart,yystop,xxstop);
1077 putstring(s_row,2,C_GENERAL_MED,msg);
1078 if (got_status == 2 || got_status == 4) { /* btm or tesseral */
1079 putstring(-1,-1,C_GENERAL_MED,"at ");
1080 sprintf(msg,"[%d,%d]",currow,curcol);
1081 putstring(-1,-1,C_GENERAL_HI,msg);
1082 }
1083 else {
1084 if (totpasses > 1) {
1085 putstring(-1,-1,C_GENERAL_MED,"pass ");
1086 sprintf(msg,"%d",curpass);
1087 putstring(-1,-1,C_GENERAL_HI,msg);
1088 putstring(-1,-1,C_GENERAL_MED," of ");
1089 sprintf(msg,"%d",totpasses);
1090 putstring(-1,-1,C_GENERAL_HI,msg);
1091 putstring(-1,-1,C_GENERAL_MED,", ");
1092 }
1093 putstring(-1,-1,C_GENERAL_MED,"at row ");
1094 sprintf(msg,"%d",currow);
1095 putstring(-1,-1,C_GENERAL_HI,msg);
1096 putstring(-1,-1,C_GENERAL_MED," col ");
1097 sprintf(msg,"%d",col);
1098 putstring(-1,-1,C_GENERAL_HI,msg);
1099 }
1100 ++s_row;
1101 }
1102 }
1103 putstring(s_row,2,C_GENERAL_MED,scalculation_time);
1104 get_calculation_time(msg,calctime);
1105 putstring(-1,-1,C_GENERAL_HI,msg);
1106 if ((got_status == 5) && (calc_status == 1)) { /* estimate total time */
1107 putstring(-1,-1,C_GENERAL_MED," estimated total time: ");
1108 get_calculation_time( msg,(long)(calctime*((dif_limit*1.0)/dif_counter)) );
1109 putstring(-1,-1,C_GENERAL_HI,msg);
1110 }
1111
1112 if ((curfractalspecific->flags&INFCALC) && (coloriter != 0)) {
1113 putstring(s_row,-1,C_GENERAL_MED,siterations);
1114 sprintf(msg," %ld of %ld",coloriter-2,maxct);
1115 putstring(s_row,-1,C_GENERAL_HI,msg);
1116 }
1117
1118 ++s_row;
1119 if(bf_math == 0)
1120 ++s_row;
1121 if (videoentry.xdots && bf_math==0) {
1122 sprintf(msg,"Video: %dx%dx%d %s %s",
1123 videoentry.xdots, videoentry.ydots, videoentry.colors,
1124 videoentry.name, videoentry.comment);
1125 putstring(s_row++,2,C_GENERAL_MED,msg);
1126 }
1127 if(!(curfractalspecific->flags&NOZOOM))
1128 {
1129 adjust_corner(); /* make bottom left exact if very near exact */
1130 if(bf_math)
1131 {
1132 int truncate, truncaterow;
1133 dec = min(320,decimals);
1134 adjust_cornerbf(); /* make bottom left exact if very near exact */
1135 cvtcentermagbf(bfXctr, bfYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
1136 /* find alignment information */
1137 msg[0] = 0;
1138 truncate = 0;
1139 if(dec < decimals)
1140 truncate = 1;
1141 truncaterow = row;
1142 putstring(++s_row,2,C_GENERAL_MED,scenter);
1143 putstring(s_row,8,C_GENERAL_MED,s_x);
1144 bftostr(msg,dec,bfXctr);
1145 if(putstringwrap(&s_row,10,78,C_GENERAL_HI,msg,5)==1)
1146 truncate = 1;
1147 putstring(++s_row,8,C_GENERAL_MED,s_y);
1148 bftostr(msg,dec,bfYctr);
1149 if(putstringwrap(&s_row,10,78,C_GENERAL_HI,msg,5)==1 || truncate)
1150 putstring(truncaterow,2,C_GENERAL_MED,struncate);
1151 putstring(++s_row,2,C_GENERAL_MED,smag);
1152 #ifdef USE_LONG_DOUBLE
1153 sprintf(msg,"%10.8Le",Magnification);
1156 #endif
1157 putstring(-1,11,C_GENERAL_HI,msg);
1158 putstring(++s_row,2,C_GENERAL_MED,sxmag);
1159 sprintf(msg,"%11.4f ",Xmagfactor);
1160 putstring(-1,-1,C_GENERAL_HI,msg);
1161 putstring(-1,-1,C_GENERAL_MED,srot);
1162 sprintf(msg,"%9.3f ",Rotation);
1163 putstring(-1,-1,C_GENERAL_HI,msg);
1164 putstring(-1,-1,C_GENERAL_MED,sskew);
1165 sprintf(msg,"%9.3f",Skew);
1166 putstring(-1,-1,C_GENERAL_HI,msg);
1167 }
1168 else /* bf != 1 */
1169 {
1170 putstring(s_row,2,C_GENERAL_MED,scornersxy);
1171 putstring(++s_row,3,C_GENERAL_MED,stop_left);
1172 sprintf(msg,"%20.16f %20.16f",xxmin,yymax);
1173 putstring(-1,17,C_GENERAL_HI,msg);
1174 putstring(++s_row,3,C_GENERAL_MED,sbottom_right);
1175 sprintf(msg,"%20.16f %20.16f",xxmax,yymin);
1176 putstring(-1,17,C_GENERAL_HI,msg);
1177
1178 if (xxmin != xx3rd || yymin != yy3rd)
1179 {
1180 putstring(++s_row,3,C_GENERAL_MED,sbottom_left);
1181 sprintf(msg,"%20.16f %20.16f",xx3rd,yy3rd);
1182 putstring(-1,17,C_GENERAL_HI,msg);
1183 }
1184 cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
1185 putstring(s_row+=2,2,C_GENERAL_MED,scenter);
1186 sprintf(msg,"%20.16f %20.16f ",Xctr,Yctr);
1187 putstring(-1,-1,C_GENERAL_HI,msg);
1188 putstring(-1,-1,C_GENERAL_MED,smag);
1189 #ifdef USE_LONG_DOUBLE
1190 sprintf(msg," %10.8Le",Magnification);
1193 #endif
1194 putstring(-1,-1,C_GENERAL_HI,msg);
1195 putstring(++s_row,2,C_GENERAL_MED,sxmag);
1196 sprintf(msg,"%11.4f ",Xmagfactor);
1197 putstring(-1,-1,C_GENERAL_HI,msg);
1198 putstring(-1,-1,C_GENERAL_MED,srot);
1199 sprintf(msg,"%9.3f ",Rotation);
1200 putstring(-1,-1,C_GENERAL_HI,msg);
1201 putstring(-1,-1,C_GENERAL_MED,sskew);
1202 sprintf(msg,"%9.3f",Skew);
1203 putstring(-1,-1,C_GENERAL_HI,msg);
1204
1205 }
1206 }
1207
1208 if(typehasparm(fractype,0,msg) || hasformparam)
1209 for (i = 0; i < MAXPARAMS; i++)
1210 {
1211 int col;
1212 char p[50];
1213 if(typehasparm(fractype,i,p))
1214 {
1215 if(k%4 == 0)
1216 {
1217 s_row++;
1218 col = 9;
1219 }
1220 else
1221 col = -1;
1222 if(k == 0) /* only true with first displayed parameter */
1223 putstring(++s_row,2,C_GENERAL_MED,sparams);
1224 sprintf(msg,"%3d: ",i+1);
1225 putstring(s_row,col,C_GENERAL_MED,msg);
1226 if(*p == '+')
1227 sprintf(msg,"%-12d",(int)param[i]);
1228 else if(*p == '#')
1229 sprintf(msg,"%-12lu",(U32)param[i]);
1230 else
1231 sprintf(msg,"%-12.9f",param[i]);
1232 putstring(-1,-1,C_GENERAL_HI,msg);
1233 k++;
1234 }
1235 }
1236 putstring(s_row+=2,2,C_GENERAL_MED,siteration_maximum);
1237 sprintf(msg,"%ld (%ld)",coloriter,maxit);
1238 putstring(-1,-1,C_GENERAL_HI,msg);
1239 putstring(-1,-1,C_GENERAL_MED,seffective_bailout);
1240 sprintf(msg,"%f",rqlim);
1241 putstring(-1,-1,C_GENERAL_HI,msg);
1242
1243 if (fractype == PLASMA || fractype == ANT || fractype == CELLULAR) {
1244 putstring(++s_row,2,C_GENERAL_MED,scurrent_rseed);
1245 sprintf(msg,"%d",rseed);
1246 putstring(-1,-1,C_GENERAL_HI,msg);
1247 }
1248
1249 if(invert) {
1250 putstring(++s_row,2,C_GENERAL_MED,sinversion_radius);
1251 sprintf(msg,"%12.9f",f_radius);
1252 putstring(-1,-1,C_GENERAL_HI,msg);
1253 putstring(-1,-1,C_GENERAL_MED,sxcenter);
1254 sprintf(msg,"%12.9f",f_xcenter);
1255 putstring(-1,-1,C_GENERAL_HI,msg);
1256 putstring(-1,-1,C_GENERAL_MED,sycenter);
1257 sprintf(msg,"%12.9f",f_ycenter);
1258 putstring(-1,-1,C_GENERAL_HI,msg);
1259 }
1260
1261 if ((s_row += 2) < 23) ++s_row;
1262 /*waitforkey:*/
1263 putstringcenter(/*s_row*/24,0,80,C_GENERAL_LO,spressanykey);
1264 movecursor(25,80);
1265 #ifdef XFRACT
1269 #endif
1270 key = getakeynohelp();
1271 if (key==F6) {
1272 unstackscreen();
1273 area();
1274 stackscreen();
1275 /* goto waitforkey;*/
1276 goto top;
1277 }
1278 else if(key==CTL_TAB || key==BACK_TAB || key==F7) {
1279 if(tab_display_2(msg))
1280 goto top;
1281 }
1282 unstackscreen();
1283 timer_start = clock_ticks(); /* tab display was "time out" */
1284 if(bf_math)
1285 {
1286 restore_stack(saved);
1287 MoveFromMemory(ptr_to_extraseg,(U16)22400,1L,0L,save_extra_handle);
1288 MemoryRelease(save_extra_handle);
1289 save_extra_handle = 0;
1290 }
1291 return(0);
1292 }
1293
1294 static void area(void)
1295 {
1296 /* apologies to UNIX folks, we PC guys have to save near space */
1297 static FCODE warning[] = {"Warning: inside may not be unique\n"};
1298 static FCODE total_area[] = {". Total area "};
1299 char far *msg;
1300 int x,y;
1301 char buf[160];
1302 long cnt=0;
1303 if (inside<0) {
1304 static FCODE msg[] = {"Need solid inside to compute area"};
1305 stopmsg(0,msg);
1306 return;
1307 }
1308 for (y=0;y<ydots;y++) {
1309 for (x=0;x<xdots;x++) {
1310 if (getcolor(x,y)==inside) {
1311 cnt++;
1312 }
1313 }
1314 }
1315 if (inside>0 && outside<0 && maxit>inside) {
1316 msg = warning;
1317 } else {
1318 msg = (char far *)"";
1319 }
1320 #ifndef XFRACT
1321 sprintf(buf,"%Fs%ld inside pixels of %ld%Fs%f",
1322 msg,cnt,(long)xdots*(long)ydots,(char far *)total_area,
1323 cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
1328 #endif
1329 stopmsg(4,buf);
1330 }
1331
1332 int endswithslash(char far *fl)
1333 {
1334 int len;
1335 len = far_strlen(fl);
1336 if(len)
1337 if(fl[--len] == SLASHC)
1338 return(1);
1339 return(0);
1340 }
1341
1342 /* --------------------------------------------------------------------- */
1343 static char seps[] = {"' ','\t',\n',\r'"};
1344 char *get_ifs_token(char *buf,FILE *ifsfile)
1345 {
1346 char *bufptr;
1347 for(;;)
1348 {
1349 if(file_gets(buf,200,ifsfile) < 0)
1350 return(NULL);
1351 else
1352 {
1353 if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
1354 *bufptr = 0;
1355 if((bufptr = strtok(buf, seps)) != NULL)
1356 return(bufptr);
1357 }
1358 }
1359 }
1360
1361 FCODE insufficient_ifs_mem[]={"Insufficient memory for IFS"};
1362 int numaffine;
1363 int ifsload() /* read in IFS parameters */
1364 {
1365 int i;
1366 FILE *ifsfile;
1367 char buf[201];
1368 char *bufptr;
1369 int ret,rowsize;
1370
1371 if (ifs_defn) { /* release prior parms */
1372 farmemfree((char far *)ifs_defn);
1373 ifs_defn = NULL;
1374 }
1375
1376 ifs_type = 0;
1377 rowsize = IFSPARM;
1378 if (find_file_item(IFSFileName,IFSName,&ifsfile, 3) < 0)
1379 return(-1);
1380
1381 file_gets(buf,200,ifsfile);
1382 if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
1383 *bufptr = 0;
1384
1385 strlwr(buf);
1386 bufptr = &buf[0];
1387 while (*bufptr) {
1388 if (strncmp(bufptr,"(3d)",4) == 0) {
1389 ifs_type = 1;
1390 rowsize = IFS3DPARM;
1391 }
1392 ++bufptr;
1393 }
1394
1395 for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
1396 ((float *)tstack)[i] = 0;
1397 i = ret = 0;
1398 bufptr = get_ifs_token(buf,ifsfile);
1399 while(bufptr != NULL)
1400 {
1401 if(sscanf(bufptr," %f ",&((float *)tstack)[i]) != 1)
1402 break ;
1403 if (++i >= NUMIFS*rowsize)
1404 {
1405 static FCODE msg[]={"IFS definition has too many lines"};
1406 stopmsg(0,msg);
1407 ret = -1;
1408 break;
1409 }
1410 if((bufptr = strtok( NULL, seps ))==NULL)
1411 {
1412 if((bufptr = get_ifs_token(buf,ifsfile)) == NULL)
1413 {
1414 ret = -1;
1415 break;
1416 }
1417 }
1418 if(ret == -1)
1419 break;
1420 if(*bufptr == '}')
1421 break;
1422 }
1423
1424 if ((i % rowsize) != 0 || *bufptr != '}') {
1425 static FCODE msg[]={"invalid IFS definition"};
1426 stopmsg(0,msg);
1427 ret = -1;
1428 }
1429 if (i == 0 && ret == 0) {
1430 static FCODE msg[]={"Empty IFS definition"};
1431 stopmsg(0,msg);
1432 ret = -1;
1433 }
1434 fclose(ifsfile);
1435
1436 if (ret == 0) {
1437 numaffine = i/rowsize;
1438 if ((ifs_defn = (float far *)farmemalloc(
1439 (long)((NUMIFS+1)*IFS3DPARM*sizeof(float)))) == NULL) {
1440 stopmsg(0,insufficient_ifs_mem);
1441 ret = -1;
1442 }
1443 else
1444 for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
1445 ifs_defn[i] = ((float *)tstack)[i];
1446 }
1447 return(ret);
1448 }
1449 /* TW 5-31-94 - added search of current directory for entry files if
1450 entry item not found */
1451
1452 int find_file_item(char *filename,char *itemname,FILE **fileptr, int itemtype)
1453 {
1454 FILE *infile=NULL;
1455 int found = 0;
1456 char parsearchname[ITEMNAMELEN + 6];
1457 char drive[FILE_MAX_DRIVE];
1458 char dir[FILE_MAX_DIR];
1459 char fname[FILE_MAX_FNAME];
1460 char ext[FILE_MAX_EXT];
1461 char fullpath[FILE_MAX_PATH];
1462 char defaultextension[5];
1463
1464
1465 splitpath(filename,drive,dir,fname,ext);
1466 makepath(fullpath,"","",fname,ext);
1467 if(stricmp(filename, CommandFile)) {
1468 if((infile=fopen(filename, "rb")) != NULL) {
1469 if(scan_entries(infile, NULL, itemname) == -1) {
1470 found = 1;
1471 }
1472 else {
1473 fclose(infile);
1474 infile = NULL;
1475 }
1476 }
1477
1478 if(!found && checkcurdir) {
1479 makepath(fullpath,"",DOTSLASH,fname,ext);
1480 if((infile=fopen(fullpath, "rb")) != NULL) {
1481 if(scan_entries(infile, NULL, itemname) == -1) {
1482 strcpy(filename, fullpath);
1483 found = 1;
1484 }
1485 else {
1486 fclose(infile);
1487 infile = NULL;
1488 }
1489 }
1490 }
1491 }
1492
1493 switch (itemtype) {
1494 case 1:
1495 strcpy(parsearchname, "frm:");
1496 strcat(parsearchname, itemname);
1497 parsearchname[ITEMNAMELEN + 5] = (char) 0; /*safety*/
1498 strcpy(defaultextension, ".frm");
1499 splitpath(searchfor.frm,drive,dir,NULL,NULL);
1500 break;
1501 case 2:
1502 strcpy(parsearchname, "lsys:");
1503 strcat(parsearchname, itemname);
1504 parsearchname[ITEMNAMELEN + 5] = (char) 0; /*safety*/
1505 strcpy(defaultextension, ".l");
1506 splitpath(searchfor.lsys,drive,dir,NULL,NULL);
1507 break;
1508 case 3:
1509 strcpy(parsearchname, "ifs:");
1510 strcat(parsearchname, itemname);
1511 parsearchname[ITEMNAMELEN + 5] = (char) 0; /*safety*/
1512 strcpy(defaultextension, ".ifs");
1513 splitpath(searchfor.ifs,drive,dir,NULL,NULL);
1514 break;
1515 default:
1516 strcpy(parsearchname, itemname);
1517 parsearchname[ITEMNAMELEN + 5] = (char) 0; /*safety*/
1518 strcpy(defaultextension, ".par");
1519 splitpath(searchfor.par,drive,dir,NULL,NULL);
1520 break;
1521 }
1522
1523 if(!found) {
1524 if((infile=fopen(CommandFile, "rb")) != NULL) {
1525 if(scan_entries(infile, NULL, parsearchname) == -1) {
1526 strcpy(filename, CommandFile);
1527 found = 1;
1528 }
1529 else {
1530 fclose(infile);
1531 infile = NULL;
1532 }
1533 }
1534 }
1535
1536 if(!found) {
1537 makepath(fullpath,drive,dir,fname,ext);
1538 if((infile=fopen(fullpath, "rb")) != NULL) {
1539 if(scan_entries(infile, NULL, itemname) == -1) {
1540 strcpy(filename, fullpath);
1541 found = 1;
1542 }
1543 else {
1544 fclose(infile);
1545 infile = NULL;
1546 }
1547 }
1548 }
1549
1550 if(!found) { /* search for file */
1551 int out;
1552 makepath(fullpath,drive,dir,"*",defaultextension);
1553 out = fr_findfirst(fullpath);
1554 while(out == 0) {
1555 char msg[200];
1556 DTA.filename[FILE_MAX_FNAME+FILE_MAX_EXT-2]=0;
1557 sprintf(msg,"Searching %13s for %s ",DTA.filename,itemname);
1558 showtempmsg(msg);
1559 if(!(DTA.attribute & SUBDIR) &&
1560 strcmp(DTA.filename,".")&&
1561 strcmp(DTA.filename,"..")) {
1562 #ifndef XFRACT
1563 strlwr(DTA.filename);
1564 #endif
1565 splitpath(DTA.filename,NULL,NULL,fname,ext);
1566 makepath(fullpath,drive,dir,fname,ext);
1567 if((infile=fopen(fullpath, "rb")) != NULL) {
1568 if(scan_entries(infile, NULL, itemname) == -1) {
1569 strcpy(filename, fullpath);
1570 found = 1;
1571 break;
1572 }
1573 else {
1574 fclose(infile);
1575 infile = NULL;
1576 }
1577 }
1578 }
1579 out = fr_findnext();
1580 }
1581 cleartempmsg();
1582 }
1583
1584 if (!found && orgfrmsearch && itemtype == 1) {
1585 splitpath(orgfrmdir,drive,dir,NULL,NULL);
1586 fname[0] = '_';
1587 fname[1] = (char) 0;
1588 if (isalpha(itemname[0])) {
1589 if (strnicmp(itemname, "carr", 4)) {
1590 fname[1] = itemname[0];
1591 fname[2] = (char) 0;
1592 }
1593 else if (isdigit(itemname[4])) {
1594 strcat(fname, "rc");
1595 fname[3] = itemname[4];
1596 fname[4] = (char) 0;
1597 }
1598 else {
1599 strcat(fname, "rc");
1600 }
1601 }
1602 else if (isdigit(itemname[0])) {
1603 strcat(fname, "num");
1604 }
1605 else {
1606 strcat(fname, "chr");
1607 }
1608 makepath(fullpath,drive,dir,fname,defaultextension);
1609 if((infile=fopen(fullpath, "rb")) != NULL) {
1610 if(scan_entries(infile, NULL, itemname) == -1) {
1611 strcpy(filename, fullpath);
1612 found = 1;
1613 }
1614 else {
1615 fclose(infile);
1616 infile = NULL;
1617 }
1618 }
1619 }
1620
1621 if(!found) {
1622 sprintf(fullpath,"'%s' file entry item not found",itemname);
1623 stopmsg(0,fullpath);
1624 return(-1);
1625 }
1626 /* found file */
1627 if(fileptr != NULL)
1628 *fileptr = infile;
1629 else if(infile != NULL)
1630 fclose(infile);
1631 return(0);
1632 }
1633
1634
1635 int file_gets(char *buf,int maxlen,FILE *infile)
1636 {
1637 int len,c;
1638 /* similar to 'fgets', but file may be in either text or binary mode */
1639 /* returns -1 at eof, length of string otherwise */
1640 if (feof(infile)) return -1;
1641 len = 0;
1642 while (len < maxlen) {
1643 if ((c = getc(infile)) == EOF || c == '\032') {
1644 if (len) break;
1645 return -1;
1646 }
1647 if (c == '\n') break; /* linefeed is end of line */
1648 if (c != '\r') buf[len++] = (char)c; /* ignore c/r */
1649 }
1650 buf[len] = 0;
1651 return len;
1652 }
1653
1654 int matherr_ct = 0;
1655
1656 #ifndef XFRACT
1657 #ifdef WINFRACT
1658 /* call this something else to dodge the QC4WIN bullet... */
1659 int win_matherr( struct exception *except ) 1660 #else
1661 int _cdecl _matherr( struct exception *except )
1662 #endif
1663 {
1664 if(debugflag != 0)
1665 {
1666 static FILE *fp=NULL;
1667 static FCODE msg[]={"Math error, but we'll try to keep going"};
1668 if(matherr_ct++ == 0)
1669 if(debugflag == 4000 || debugflag == 3200)
1670 stopmsg(0,msg);
1671 if(fp==NULL)
1672 fp = fopen("matherr","w");
1673 if(matherr_ct < 100)
1674 {
1675 fprintf(fp,"err #%d: %d\nname: %s\narg: %e\n",
1676 matherr_ct, except->type, except->name, except->arg1);
1677 fflush(fp);
1678 }
1679 else
1680 matherr_ct = 100;
1681
1682 }
1683 if( except->type == DOMAIN )
1684 {
1685 char buf[40];
1686 sprintf(buf,"%e",except->arg1);
1687 /* This test may be unnecessary - from my experiments if the
1688 argument is too large or small the error is TLOSS not DOMAIN */
1689 if(strstr(buf,"IN")||strstr(buf,"NAN")) /* trashed arg? */
1690 /* "IND" with MSC, "INF" with BC++ */
1691 {
1692 if( strcmp( except->name, s_sin ) == 0 )
1693 {
1694 except->retval = 0.0;
1695 return(1);
1696 }
1697 else if( strcmp( except->name, s_cos ) == 0 )
1698 {
1699 except->retval = 1.0;
1700 return(1);
1701 }
1702 else if( strcmp( except->name, s_log ) == 0 )
1703 {
1704 except->retval = 1.0;
1705 return(1);
1706 }
1707 }
1708 }
1709 if( except->type == TLOSS )
1710 {
1711 /* try valiantly to keep going */
1712 if( strcmp( except->name, s_sin ) == 0 )
1713 {
1714 except->retval = 0.5;
1715 return(1);
1716 }
1717 else if( strcmp( except->name, s_cos ) == 0 )
1718 {
1719 except->retval = 0.5;
1720 return(1);
1721 }
1722 }
1723 /* shucks, no idea what went wrong, but our motto is "keep going!" */
1724 except->retval = 1.0;
1725 return(1);
1726 }
1727 #endif
1728
1729 void roundfloatd(double *x) /* make double converted from float look ok */
1730 {
1731 char buf[30];
1732 sprintf(buf,"%-10.7g",*x);
1733 *x = atof(buf);
1734 }
1735
1736 void fix_inversion(double *x) /* make double converted from string look ok */
1737 {
1738 char buf[30];
1739 sprintf(buf,"%-1.15lg",*x);
1740 *x = atof(buf);
1741 }
1742
1743 /* fake a keystroke, returns old pending key */
1744 int ungetakey(int key)
1745 {
1746 int old;
1747 old = keybuffer;
1748 keybuffer = key;
1749 return(old);
1750 }
1751
1752 #if _MSC_VER == 800
1753 #ifdef FIXTAN_DEFINED
1754 #undef tan
1755 /* !!!!! stupid MSVC tan(x) bug fix !!!!!!!! */
1756 /* tan(x) can return -tan(x) if -pi/2 < x < pi/2 */
1757 /* if tan(x) has been called before outside this range. */
1758 double fixtan( double x )
1759 {
1760 double y;
1761
1762 y = tan(x);
1763 if ((x > -PI/2 && x < 0 && y > 0) || (x > 0 && x < PI/2 && y < 0))
1764 y = -y;
1765 return y;
1766 }
1767 #define tan fixtan
1768 #endif
1769 #endif
1770
1771
1772