/* encoder.c - GIF Encoder and associated routines */ #include #include #ifndef XFRACT #include #endif /* see Fractint.c for a description of the "include" hierarchy */ #include "port.h" #include "prototyp.h" #include "fractype.h" #ifdef WINFRACT extern int OperCancelled; void OpenStatusBox(void); void UpdateStatusBox(unsigned long Partial, unsigned long Total); void CloseStatusBox(void); #endif static int inittable(void); static int _fastcall shftwrite(BYTE * color, int numcolors); static int _fastcall raster(unsigned int); static int _fastcall extend_blk_len(int datalen); static int _fastcall put_extend_blk(int block_id, int block_len, char far * block_data); static int _fastcall store_item_name(char *); static void _fastcall setup_save_info(struct fractal_info far * save_info); #ifdef XFRACT int decode_fractal_info(); #endif /* Save-To-Disk Routines (GIF) GIF and 'Graphics Interchange Format' are trademarks (tm) of Compuserve Incorporated, an H&R Block Company. The following routines perform the GIF encoding when the 's' key is pressed. The routines refer to several variables that are declared elsewhere [colors, xdots, ydots, and 'dacbox'], and rely on external routines to actually read and write screen pixels [getcolor(x,y) and putcolor(x,y,color)]. (Writing pixels is just stuffed in here as a sort of visual status report, and has nothing to do with any GIF function.) They also rely on the existence of an externally-defined 64K dataspace and they use the routines 'toextra()' and 'cmpextra()' to deal with that dataspace (in the same manner as 'memcpy()' and 'memcmp()' would). Otherwise, they perform a generic GIF-encoder function. Note that these routines use small string- and hash-tables, and "flush" the GIF entries whenever the hash-table gets two-thirds full or the string table gets full. They also use the GIF encoding technique of limiting the encoded string length to a specific size, "adding" a string to the hash table at that point even if a matching string exists ("adding" is in quotes, because if a matching string exists we can increment the code counter but safely throw the duplicate string away, saving both string space and a hash table entry). This results in relatively good speed and small data space, but at the expense of compression efficiency (filesize). These trade-offs could be adjusted by modifying the #DEFINEd variables below. Note that the 'strlocn' and 'teststring' routines are declared to be external just so that they can be defined (and the space re-used) elsewhere. The actual declarations are in the assembler code. */ #define MAXTEST 100 /* maximum single string length */ #define MAXSTRING 60000L /* total space reserved for strings */ /* maximum number of strings available */ #define MAXENTRY 5003 /* (a prime number is best for hashing) */ #ifdef XFRACT unsigned int strlocn[10240]; BYTE teststring[MAXTEST]; BYTE block[266]; /* GIF-encoded blocks go here */ #endif static int numsaves = 0; /* For adjusting 'save-to-disk' filenames */ static FILE *out; static int last_colorbar; static int save16bit; static int outcolor1s, outcolor2s; long max_nextentry; static int lentest, lastentry, numentries, numrealentries; static unsigned int nextentry; static int clearcode, endcode; static unsigned int hashcode; static BYTE blockcount; static int startbits, codebits, bytecount, bitcount; static BYTE paletteBW[] = { /* B&W palette */ 0, 0, 0, 63, 63, 63, }; static BYTE paletteCGA[] = { /* 4-color (CGA) palette */ 0, 0, 0, 21, 63, 63, 63, 21, 63, 63, 63, 63, }; static BYTE paletteEGA[] = { /* 16-color (EGA/CGA) pal */ 0, 0, 0, 0, 0, 42, 0, 42, 0, 0, 42, 42, 42, 0, 0, 42, 0, 42, 42, 21, 0, 42, 42, 42, 21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63, 63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63, }; int savetodisk(char *filename) /* save-to-disk routine */ { char tmpmsg[41]; /* before openfile in case of overrun */ char openfile[FILE_MAX_PATH], openfiletype[10]; char tmpfile[FILE_MAX_PATH]; char *period; int newfile; int i, j, outcolor1, outcolor2, interrupted; restart: save16bit = disk16bit; if (gif87a_flag) /* not storing non-standard fractal info */ save16bit = 0; strcpy(openfile, filename); /* decode and open the filename */ strcpy(openfiletype, DEFAULTFRACTALTYPE); /* determine the file * extension */ if (save16bit) strcpy(openfiletype, ".pot"); if ((period = has_ext(openfile)) != NULL) { strcpy(openfiletype, period); *period = 0; } if (resave_flag != 1) updatesavename(filename); /* for next time */ strcat(openfile, openfiletype); strcpy(tmpfile, openfile); if (access(openfile, 0) != 0)/* file doesn't exist */ newfile = 1; else { /* file already exists */ static FCODE fractint_tmp[] = {"fractint.tmp"}; if (overwrite == 0) { if (resave_flag == 0) goto restart; if (started_resaves == 0) { /* first save of a savetime set */ updatesavename(filename); goto restart; } } if (access(openfile, 2) != 0) { sprintf(tmpmsg, s_cantwrite, openfile); stopmsg(0, tmpmsg); return -1; } newfile = 0; i = strlen(tmpfile); while (--i >= 0 && tmpfile[i] != SLASHC) tmpfile[i] = 0; far_strcat(tmpfile, fractint_tmp); } started_resaves = (resave_flag == 1) ? 1 : 0; if (resave_flag == 2) /* final save of savetime set? */ resave_flag = 0; if ((out = fopen(tmpfile, "wb")) == NULL) { sprintf(tmpmsg, s_cantcreate, tmpfile); stopmsg(0, tmpmsg); return -1; } if (dotmode == 11) { /* disk-video */ char buf[61]; extract_filename(tmpmsg, openfile); sprintf(buf, "Saving %s", tmpmsg); dvid_status(1, buf); } #ifdef XFRACT else { putstring(3, 0, 0, "Saving to:"); putstring(4, 0, 0, openfile); putstring(5, 0, 0, " "); } #endif busy = 1; if (debugflag != 200) interrupted = encoder(); else interrupted = timer(2, NULL); /* invoke encoder() via timer */ busy = 0; fclose(out); if (interrupted) { static FCODE s_delete[] = {"delete the file,\ncontinue to keep the partial image."}; static FCODE s_retain[] = {"retain the original file,\ncontinue to replace original with new partial image."}; char buf[200]; sprintf(buf, "Save of %s interrupted.\nCancel to ", openfile); if (newfile) far_strcat(buf,s_delete); else far_strcat(buf,s_retain); interrupted = 1; if (stopmsg(2, buf) < 0) { interrupted = -1; unlink(tmpfile); } } if (newfile == 0 && interrupted >= 0) { /* replace the real file */ unlink(openfile); /* success assumed since we checked */ rename(tmpfile, openfile);/* earlier with access */ } if (dotmode != 11) { /* supress this on disk-video */ if (active_system == 0) { /* no bars in Windows version */ outcolor1 = outcolor1s; outcolor2 = outcolor2s; for (j = 0; j <= last_colorbar; j++) { if ((j & 4) == 0) { if (++outcolor1 >= colors) outcolor1 = 0; if (++outcolor2 >= colors) outcolor2 = 0; } for (i = 0; 250 * i < xdots; i++) { /* clear vert status bars */ putcolor(i, j, getcolor(i, j) ^ outcolor1); putcolor(xdots - 1 - i, j, getcolor(xdots - 1 - i, j) ^ outcolor2); } } } #ifdef XFRACT putstring(5, 0, 0, "Saving done\n"); #endif } else /* disk-video */ dvid_status(1, ""); if (interrupted) { static FCODE msg[] = {" *interrupted* save "}; texttempmsg(msg); if (initbatch >= 1) initbatch = 3; /* if batch mode, set error level */ return -1; } if (timedsave == 0) { buzzer(0); if (initbatch == 0) { extract_filename(tmpfile, openfile); sprintf(tmpmsg, " File saved as %s ", tmpfile); texttempmsg(tmpmsg); } } if (initsavetime < 0) goodbye(); return 0; } int encoder() { int i, ydot, xdot, color, outcolor1, outcolor2; int width; int rownum, rowlimit; unsigned int hashentry; BYTE bitsperpixel, x; int entrynum; struct fractal_info save_info; unsigned int maxstring; max_nextentry=0; ydot = 0; /* arbitrary math uses top of extraseg - steal from encoder if necessary */ if (bf_save_len) { maxstring = (unsigned int) (0x10000l - (bf_save_len + 2) * 22); maxstring = min((unsigned int) MAXSTRING, maxstring); } else maxstring = (unsigned int) MAXSTRING; if (initbatch) /* flush any impending keystrokes */ while (keypressed()) getakey(); setup_save_info(&save_info); #ifndef XFRACT bitsperpixel = 0; /* calculate bits / pixel */ for (i = colors; i >= 2; i /= 2) bitsperpixel++; startbits = bitsperpixel + 1;/* start coding with this many bits */ if (colors == 2) startbits++; /* B&W Klooge */ #else if (colors == 2) { bitsperpixel = 1; startbits = 3; } else { bitsperpixel = 8; startbits = 9; } #endif clearcode = 1 << (startbits - 1); /* set clear and end codes */ endcode = clearcode + 1; outcolor1 = 0; /* use these colors to show progress */ outcolor2 = 1; /* (this has nothing to do with GIF) */ if (colors > 2) { outcolor1 = 2; outcolor2 = 3; } if (((++numsaves) & 1) == 0) { /* reverse the colors on alt saves */ i = outcolor1; outcolor1 = outcolor2; outcolor2 = i; } outcolor1s = outcolor1; outcolor2s = outcolor2; if (gif87a_flag == 1) { if (fwrite("GIF87a", 6, 1, out) != 1) goto oops; /* old GIF Signature */ } else { if (fwrite("GIF89a", 6, 1, out) != 1) goto oops; /* new GIF Signature */ } width = xdots; rowlimit = ydots; if (save16bit) { /* pot16bit info is stored as: file: double width rows, right side * of row is low 8 bits diskvid: ydots rows of colors followed by ydots * rows of low 8 bits decoder: returns (row of color info then row of * low 8 bits) * ydots */ rowlimit <<= 1; width <<= 1; } if (write2(&width, 2, 1, out) != 1) goto oops; /* screen descriptor */ if (write2(&ydots, 2, 1, out) != 1) goto oops; x = (BYTE) (128 + ((6 - 1) << 4) + (bitsperpixel - 1)); /* color resolution == 6 * bits worth */ if (write1(&x, 1, 1, out) != 1) goto oops; if (fputc(0, out) != 0) goto oops; /* background color */ i = 0; if (viewwindow /* less than full screen? */ && (viewxdots == 0 || viewydots == 0)) /* and we picked the dots? */ i = (int) (((double) sydots / (double) sxdots) * 64.0 / screenaspect - 14.5); else /* must risk loss of precision if numbers low */ i = (int) ((((double) ydots / (double) xdots) / finalaspectratio) * 64 - 14.5); if (i < 1) i = 1; if (i > 255) i = 255; if (gif87a_flag) i = 0; /* for some decoders which can't handle * aspect */ if (fputc(i, out) != i) goto oops; /* pixel aspect ratio */ #ifndef XFRACT if (colors == 256) { /* write out the 256-color palette */ if (gotrealdac) { /* got a DAC - must be a VGA */ if (!shftwrite((BYTE *) dacbox, colors)) goto oops; #else if (colors > 2) { if (gotrealdac) { /* got a DAC - must be a VGA */ if (!shftwrite((BYTE *) dacbox, 256)) goto oops; #endif } else { /* uh oh - better fake it */ for (i = 0; i < 256; i += 16) if (!shftwrite(paletteEGA, 16)) goto oops; } } if (colors == 2) { /* write out the B&W palette */ if (!shftwrite(paletteBW, colors)) goto oops; } #ifndef XFRACT if (colors == 4) { /* write out the CGA palette */ if (!shftwrite(paletteCGA, colors)) goto oops; } if (colors == 16) { /* Either EGA or VGA */ if (gotrealdac) { if (!shftwrite((BYTE *) dacbox, colors)) goto oops; } else { /* no DAC - must be an EGA */ if (!shftwrite(paletteEGA, colors)) goto oops; } } #endif if (fwrite(",", 1, 1, out) != 1) goto oops; /* Image Descriptor */ i = 0; if (write2(&i, 2, 1, out) != 1) goto oops; if (write2(&i, 2, 1, out) != 1) goto oops; if (write2(&width, 2, 1, out) != 1) goto oops; if (write2(&ydots, 2, 1, out) != 1) goto oops; if (write1(&i, 1, 1, out) != 1) goto oops; bitsperpixel = (BYTE) (startbits - 1); /* raster data starts here */ if (write1(&bitsperpixel, 1, 1, out) != 1) goto oops; codebits = startbits; /* start encoding */ if (!raster(9999)) goto oops; /* initialize the raster routine */ if (!inittable()) goto oops; /* initialize the LZW tables */ for (rownum = 0; rownum < ydots; rownum++ #ifdef WINFRACT ,UpdateStatusBox(rownum, ydots) #endif ) { /* scan through the dots */ for (ydot = rownum; ydot < rowlimit; ydot += ydots) { for (xdot = 0; xdot < xdots; xdot++) { if (save16bit == 0 || ydot < ydots) color = getcolor(xdot, ydot); else color = readdisk(xdot + sxoffs, ydot + syoffs); teststring[0] = (BYTE)++ lentest; teststring[lentest] = (BYTE) color; if (lentest == 1) { /* root entry? */ lastentry = color; continue; } if (lentest == 2) /* init the hash code */ hashcode = 301 * (teststring[1] + 1); hashcode *= (color + lentest); /* update the hash code */ hashentry = ++hashcode % MAXENTRY; for (i = 0; i < MAXENTRY; i++) { if (++hashentry >= MAXENTRY) hashentry = 0; if (cmpextra(strlocn[hashentry] + sizeof(int), (char *) teststring, lentest + 1) == 0) break; if (strlocn[hashentry] == 0) i = MAXENTRY; } /* found an entry and string length isn't too bad */ if (strlocn[hashentry] != 0 && lentest < MAXTEST - 1 - (int)sizeof(int) - lzw[0]) { fromextra(strlocn[hashentry], (char *) &entrynum, sizeof(int)); lastentry = entrynum; continue; } if (!raster(lastentry)) goto oops; /* write entry */ numentries++; /* act like you added one, anyway */ if (strlocn[hashentry] == 0) { /* add new string, if any */ entrynum = numentries + endcode; strlocn[hashentry] = nextentry; toextra(nextentry, (char *) &entrynum, sizeof(int)); toextra(nextentry + sizeof(int), (char *) teststring, lentest + 1); nextentry += lentest + 1 + sizeof(int); if((long)nextentry > max_nextentry) max_nextentry = nextentry; numrealentries++; } teststring[0] = 1; /* reset current entry */ teststring[1] = (BYTE) color; lentest = 1; lastentry = color; if ((numentries + endcode) == (1 << codebits)) codebits++; /* use longer encoding */ if (numentries + endcode > 4093 || /* out of room? */ numrealentries > (MAXENTRY * 2) / 3 || nextentry > maxstring - MAXTEST - 1 - 2 * sizeof(int) - lzw[1]) { if (!raster(lastentry)) goto oops; /* flush & restart */ if (!inittable()) goto oops; } } if (dotmode != 11 /* supress this on disk-video */ && active_system == 0 /* and in Windows version */ && ydot == rownum) { if ((ydot & 4) == 0) { if (++outcolor1 >= colors) outcolor1 = 0; if (++outcolor2 >= colors) outcolor2 = 0; } for (i = 0; 250 * i < xdots; i++) { /* display vert status bars */ /* (this is NOT GIF-related) */ /* PB Changed following code to xor color, so that image can * be restored at end and resumed putcolor( * i,ydot,outcolor1); putcolor(xdots-1-i,ydot,outcolor2); */ putcolor(i, ydot, getcolor(i, ydot) ^ outcolor1); putcolor(xdots - 1 - i, ydot, getcolor(xdots - 1 - i, ydot) ^ outcolor2); } last_colorbar = ydot; } #ifdef WINFRACT keypressed(); if (OperCancelled) #else if (keypressed()) /* keyboard hit - bail out */ #endif ydot = rownum = 9999; } } if (!raster(lastentry)) goto oops; /* tidy up - dump the last code */ if (!raster(endcode)) goto oops; /* finish the map */ if (fputc(0, out) != 0) goto oops; /* raster data ends here */ if (gif87a_flag == 0) { /* store non-standard fractal info */ /* loadfile.c has notes about extension block structure */ if (ydot >= 9999) save_info.calc_status = 0; /* partial save is not resumable */ save_info.tot_extend_len = 0; if (resume_info != NULL && save_info.calc_status == 2) { /* resume info block, 002 */ save_info.tot_extend_len += extend_blk_len(resume_len); if (!put_extend_blk(2, resume_len, resume_info)) goto oops; } if (save_info.fractal_type == FORMULA || save_info.fractal_type == FFORMULA) save_info.tot_extend_len += store_item_name(FormName); if (save_info.fractal_type == LSYSTEM) save_info.tot_extend_len += store_item_name(LName); if (save_info.fractal_type == IFS || save_info.fractal_type == IFS3D) save_info.tot_extend_len += store_item_name(IFSName); if (display3d <= 0 && rangeslen) { /* ranges block, 004 */ save_info.tot_extend_len += extend_blk_len(rangeslen * 2); #ifdef XFRACT fix_ranges(ranges, rangeslen, 0); put_extend_blk(4, rangeslen * 2, (char far *) ranges); fix_ranges(ranges, rangeslen, 0); #else if (!put_extend_blk(4, rangeslen * 2, (char far *) ranges)) goto oops; #endif } /* Extended parameters block 005 */ if (bf_math) { save_info.tot_extend_len += extend_blk_len(22 * (bflength + 2)); /* note: this assumes variables allocated in order starting with * bfxmin in init_bf2() in BIGNUM.C */ if (!put_extend_blk(5, 22 * (bflength + 2), (char far *) bfxmin)) goto oops; } /* main and last block, 001 */ save_info.tot_extend_len += extend_blk_len(FRACTAL_INFO_SIZE); #ifdef XFRACT decode_fractal_info(&save_info, 0); #endif if (!put_extend_blk(1, FRACTAL_INFO_SIZE, (char far *) &save_info)) { goto oops; } } if (fwrite(";", 1, 1, out) != 1) goto oops; /* GIF Terminator */ return ((ydot < 9999) ? 0 : 1); oops: { static FCODE msg[] = {"Error Writing to disk (Disk full?)"}; fflush(out); stopmsg(0,msg); return 1; } } /* shift IBM colors to GIF */ static int _fastcall shftwrite(BYTE * color, int numcolors) { BYTE thiscolor; int i, j; for (i = 0; i < numcolors; i++) for (j = 0; j < 3; j++) { thiscolor = color[3 * i + j]; thiscolor = (BYTE) (thiscolor << 2); thiscolor = (BYTE) (thiscolor + (BYTE) (thiscolor >> 6)); if (fputc(thiscolor, out) != (int) thiscolor) return (0); } return (1); } static int inittable() /* routine to init tables */ { int i; if (!raster(clearcode)) return (0); /* signal that table is initialized */ numentries = 0; /* initialize the table */ numrealentries = 0; nextentry = 1; lentest = 0; codebits = startbits; toextra(0, "\0", 1); /* clear the hash entries */ for (i = 0; i < MAXENTRY; i++) strlocn[i] = 0; return (1); } /* routine to block and output codes */ static int _fastcall raster(unsigned int code) { unsigned int icode, i, j; if (code == 9999) { /* special start-up signal */ bytecount = 0; bitcount = 0; for (i = 0; i < 266; i++) block[i] = 0; return (1); } icode = code << bitcount; /* update the bit string */ block[bytecount] |= (icode & 255); block[bytecount + 1] |= ((icode >> 8) & 255); icode = (code >> 8) << bitcount; block[bytecount + 2] |= ((icode >> 8) & 255); bitcount += codebits; while (bitcount >= 8) { /* locate next starting point */ bitcount -= 8; bytecount++; } if (bytecount > 250 || code == (unsigned int) endcode) { /* time to write a block */ if (code == (unsigned int) endcode) while (bitcount > 0) { /* if EOF, find the real end */ bitcount -= 8; bytecount++; } i = bytecount; blockcount = (BYTE) i; if (write1(&blockcount, 1, 1, out) != 1) return (0); /* write the block */ if (fwrite(block, i, 1, out) != 1) return (0); bytecount = 0; /* now re-start the block */ for (j = 0; j < 5; j++) /* (may have leftover bits) */ block[j] = block[j + i]; for (j = 5; j < 266; j++) block[j] = 0; } return (1); } static int _fastcall extend_blk_len(int datalen) { return (datalen + (datalen + 254) / 255 + 15); /* data + 1.per.block + 14 for id + 1 for null at end */ } static int _fastcall put_extend_blk(int block_id, int block_len, char far * block_data) { int i, j; char header[15]; strcpy(header, "!\377\013fractint"); sprintf(&header[11], "%03u", block_id); if (fwrite(header, 14, 1, out) != 1) return (0); i = (block_len + 254) / 255; while (--i >= 0) { block_len -= (j = min(block_len, 255)); if (fputc(j, out) != j) return (0); while (--j >= 0) fputc(*(block_data++), out); } if (fputc(0, out) != 0) return (0); return (1); } static int _fastcall store_item_name(char *nameptr) { struct formula_info fsave_info; int i; for (i = 0; i < 40; i++) fsave_info.form_name[i] = 0; /* initialize string */ strcpy(fsave_info.form_name, nameptr); if (fractype == FORMULA || fractype == FFORMULA) { fsave_info.uses_p1 = (short) uses_p1; fsave_info.uses_p2 = (short) uses_p2; fsave_info.uses_p3 = (short) uses_p3; } else { fsave_info.uses_p1 = 0; fsave_info.uses_p2 = 0; fsave_info.uses_p3 = 0; } for (i = 0; i < sizeof(fsave_info.future) / sizeof(short); i++) fsave_info.future[i] = 0; /* formula/lsys/ifs info block, 003 */ put_extend_blk(3, sizeof(fsave_info), (char far *) &fsave_info); return (extend_blk_len(sizeof(fsave_info))); } static void _fastcall setup_save_info(struct fractal_info far * save_info) { int i; if (fractype != FORMULA && fractype != FFORMULA) maxfn = 0; /* set save parameters in save structure */ far_strcpy(save_info->info_id, INFO_ID); save_info->version = 12; /* file version, independent of system */ /* increment this EVERY time the fractal_info structure changes */ if (maxit <= SHRT_MAX) save_info->iterationsold = (short) maxit; else save_info->iterationsold = (short) SHRT_MAX; save_info->fractal_type = (short) fractype; save_info->xmin = xxmin; save_info->xmax = xxmax; save_info->ymin = yymin; save_info->ymax = yymax; save_info->creal = param[0]; save_info->cimag = param[1]; save_info->videomodeax = (short) videoentry.videomodeax; save_info->videomodebx = (short) videoentry.videomodebx; save_info->videomodecx = (short) videoentry.videomodecx; save_info->videomodedx = (short) videoentry.videomodedx; save_info->dotmode = (short) (videoentry.dotmode % 100); save_info->xdots = (short) videoentry.xdots; save_info->ydots = (short) videoentry.ydots; save_info->colors = (short) videoentry.colors; save_info->parm3 = 0; /* pre version==7 fields */ save_info->parm4 = 0; save_info->dparm3 = param[2]; save_info->dparm4 = param[3]; save_info->dparm5 = param[4]; save_info->dparm6 = param[5]; save_info->dparm7 = param[6]; save_info->dparm8 = param[7]; save_info->dparm9 = param[8]; save_info->dparm10 = param[9]; save_info->fillcolor = (short) fillcolor; save_info->potential[0] = (float) potparam[0]; save_info->potential[1] = (float) potparam[1]; save_info->potential[2] = (float) potparam[2]; save_info->rflag = (short) rflag; save_info->rseed = (short) rseed; save_info->inside = (short) inside; if (LogFlag <= SHRT_MAX) save_info->logmapold = (short) LogFlag; else save_info->logmapold = (short) SHRT_MAX; save_info->invert[0] = (float) inversion[0]; save_info->invert[1] = (float) inversion[1]; save_info->invert[2] = (float) inversion[2]; save_info->decomp[0] = (short) decomp[0]; save_info->biomorph = (short) usr_biomorph; save_info->symmetry = (short) forcesymmetry; for (i = 0; i < 16; i++) save_info->init3d[i] = (short) init3d[i]; save_info->previewfactor = (short) previewfactor; save_info->xtrans = (short) xtrans; save_info->ytrans = (short) ytrans; save_info->red_crop_left = (short) red_crop_left; save_info->red_crop_right = (short) red_crop_right; save_info->blue_crop_left = (short) blue_crop_left; save_info->blue_crop_right = (short) blue_crop_right; save_info->red_bright = (short) red_bright; save_info->blue_bright = (short) blue_bright; save_info->xadjust = (short) xadjust; save_info->yadjust = (short) yadjust; save_info->eyeseparation = (short) eyeseparation; save_info->glassestype = (short) glassestype; save_info->outside = (short) outside; save_info->x3rd = xx3rd; save_info->y3rd = yy3rd; save_info->calc_status = (short) calc_status; save_info->stdcalcmode = (char) ((three_pass && stdcalcmode == '3') ? 127 : stdcalcmode); if (distest <= 32000) save_info->distestold = (short) distest; else save_info->distestold = 32000; save_info->floatflag = floatflag; if (bailout >= 4 && bailout <= 32000) save_info->bailoutold = (short) bailout; else save_info->bailoutold = 0; save_info->calctime = calctime; save_info->trigndx[0] = trigndx[0]; save_info->trigndx[1] = trigndx[1]; save_info->trigndx[2] = trigndx[2]; save_info->trigndx[3] = trigndx[3]; save_info->finattract = (short) finattract; save_info->initorbit[0] = initorbit.x; save_info->initorbit[1] = initorbit.y; save_info->useinitorbit = useinitorbit; save_info->periodicity = (short) periodicitycheck; save_info->pot16bit = (short) disk16bit; save_info->faspectratio = finalaspectratio; save_info->system = (short) save_system; if (check_back()) save_info->release = (short) min(save_release, release); else save_info->release = (short) release; save_info->flag3d = (short) display3d; save_info->ambient = (short) Ambient; save_info->randomize = (short) RANDOMIZE; save_info->haze = (short) haze; save_info->transparent[0] = (short) transparent[0]; save_info->transparent[1] = (short) transparent[1]; save_info->rotate_lo = (short) rotate_lo; save_info->rotate_hi = (short) rotate_hi; save_info->distestwidth = (short) distestwidth; save_info->mxmaxfp = mxmaxfp; save_info->mxminfp = mxminfp; save_info->mymaxfp = mymaxfp; save_info->myminfp = myminfp; save_info->zdots = (short) zdots; save_info->originfp = originfp; save_info->depthfp = depthfp; save_info->heightfp = heightfp; save_info->widthfp = widthfp; save_info->distfp = distfp; save_info->eyesfp = eyesfp; save_info->orbittype = (short) neworbittype; save_info->juli3Dmode = (short) juli3Dmode; save_info->maxfn = maxfn; save_info->inversejulia = (short) ((major_method << 8) + minor_method); /* MVS */ save_info->bailout = bailout; save_info->bailoutest = (short) bailoutest; save_info->iterations = maxit; save_info->bflength = (short) bnlength; save_info->bf_math = (short) bf_math; save_info->old_demm_colors = (short) old_demm_colors; save_info->logmap = LogFlag; save_info->distest = distest; save_info->dinvert[0] = inversion[0]; save_info->dinvert[1] = inversion[1]; save_info->dinvert[2] = inversion[2]; save_info->logcalc = (short) Log_Fly_Calc; save_info->stoppass = (short) stoppass; for (i = 0; i < sizeof(save_info->future) / sizeof(short); i++) save_info->future[i] = 0; }