/* Hello reader! * Are you sure you want read this? Its very cryptic and strange code. YOU * HAVE BEEN WARNED! Its purpose is to genereate as fast as possible * calculation loops for various formulas/algorithms. It uses lots of * coprocesor magic. It is included from formulas.c */ #ifndef VARIABLES /*supply defaultd values */ #define VARIABLES #endif #ifndef PRETEST #define PRETEST 0 #endif #ifndef INIT #define INIT #endif #ifndef POSTCALC #define POSTCALC #endif #ifndef PRESMOOTH #define PRESMOOTH zre=rp+ip #endif #ifndef UFORMULA #define UFORMULA FORMULA #endif #ifndef UEND #define UEND #endif #ifndef SAVE #define SAVE #endif #ifndef SAVEVARIABLES #define SAVEVARIABLES #endif #ifndef RESTORE #define RESTORE #endif #ifndef RANGE #define RANGE 2 #endif #ifndef __GNUC__ #undef USEHACKS #endif #ifndef __i386__ #undef USEHACKS #endif #ifdef NOASSEMBLY #undef USEHACKS #endif /* Prepare main loop */ #ifndef NSFORMULALOOP #define NSFORMULALOOP(iter) \ do \ { /*try first 8 iterations */ \ FORMULA; \ iter--; \ } \ while (BTEST && iter) #endif #ifndef SFORMULALOOP #define SFORMULALOOP(iter) \ do \ { /*try first 8 iterations */ \ SAVEZMAG; \ FORMULA; \ iter--; \ } \ while (BTEST && iter) #endif #ifndef FORMULALOOP #ifdef SMOOTHMODE #define FORMULALOOP SFORMULALOOP #else #define FORMULALOOP NSFORMULALOOP #endif #endif #ifdef USEHACKS #ifdef RPIP #define I386HACK1 __asm__ ("#HACK1" : \ : \ "m" (szre), \ "m" (szim) \ ); #define I386HACK __asm__ ("#HACK" : \ : \ "f" (zre), \ "f" (zim) \ ); #else #define I386HACK __asm__ ("#HACK" : \ : \ "f" (zre), \ "f" (zim) \ ); #endif #else #define I386HACK #define I386HACK1 #endif #ifdef SMOOTHMODE #ifdef CUSTOMSAVEZMAG #define SAVEZMAG CUSTOMSAVEZMAG; #else #define SAVEZMAG szmag=rp+ip; #endif #else #define SAVEZMAG #endif #ifdef UNCOMPRESS /*uncompressed version of loop */ #ifdef SMOOTHMODE static unsigned int FUNCTYPE SCALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE SCALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #else static unsigned int FUNCTYPE CALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned CALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #endif { register unsigned int iter = cfractalc.maxiter; number_t szre = 0, szim = 0; #ifdef RPIP register number_t rp = 0, ip; #endif #ifdef SMOOTHMODE number_t szmag = 0; #endif SAVEVARIABLES VARIABLES; INIT; if (PRETEST) iter = 0; else { #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif if (iter < 16) { I386HACK1; I386HACK; /*try first 8 iterations */ if (BTEST && iter) { FORMULALOOP(iter); } /* while (BTEST && iter) { SAVEZMAG; FORMULA; iter--; } */ } else { iter = 8 + (cfractalc.maxiter & 7); I386HACK1; I386HACK; /*try first 8 iterations */ if (BTEST && iter) { FORMULALOOP(iter); } /* while (BTEST && iter) { SAVEZMAG; FORMULA; iter--; } */ if (BTEST) { iter = (cfractalc.maxiter - 8) & (~7); iter >>= 3; I386HACK1; I386HACK; /*do next 8 iteration w/o out of bounds checking */ do { /*hmm..we are probably in some deep area. */ szre = zre; /*save current possition */ szim = zim; SAVE; UFORMULA; UFORMULA; UFORMULA; UFORMULA; UFORMULA; UFORMULA; UFORMULA; UFORMULA; UEND; iter--; } while (BTEST && iter); if (!(BTEST)) { /*we got out of bounds */ iter <<= 3; iter += 8; /*restore saved possition */ RESTORE; zre = szre; zim = szim; #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif I386HACK1; I386HACK; FORMULALOOP(iter); /* do { SAVEZMAG FORMULA; iter--; } while (BTEST && iter); */ } } else iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7); } } #ifdef SMOOTHMODE if (iter) SMOOTHOUTPUT(); POSTCALC; iter = cfractalc.maxiter - iter; INOUTPUT(); #else POSTCALC; iter = cfractalc.maxiter - iter; OUTPUT(); #endif } #else #ifdef SMOOTHMODE static unsigned int FUNCTYPE SCALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE SCALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #else static unsigned int FUNCTYPE CALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE CALC(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #endif { register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ; #ifdef RPIP register number_t rp, ip; #endif #ifdef SMOOTHMODE number_t szmag = 0; #endif VARIABLES; INIT; if (PRETEST) iter = 0; else { #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif if (BTEST && iter) { FORMULALOOP(iter); } /* while (BTEST && iter) { I386HACK; SAVEZMAG FORMULA; iter--; } */ } #ifdef SMOOTHMODE if (iter) SMOOTHOUTPUT(); POSTCALC; iter = cfractalc.maxiter - iter; INOUTPUT(); #else POSTCALC; iter = cfractalc.maxiter - iter; OUTPUT(); #endif } #endif /*F. : Periodicity checking rountines. (16-02-97) All comments preceded by F. are mine (Fabrice Premel premelfa@etu.utc.fr). Tried to make code as efficient as possible. Next to do is convert lim in a variable that would be updated sometimes I'll try to make here a short explanation on periodicity checking : first, we'll define 2 variables : whentosave and whenincsave, which are, respectively, a measure of when we have to update saved values to be checked, and when to increase interval between 2 updates, as if they're too close, we'll miss large periods. We save Z at the beginning, and then we compare each new iteration with this Z, and if naerly equal, we declare the suite to be periodic. When ( iter mod whentosave ) == 0, we store a new value, and we repeat. UNCOMPRESSed form is just an extension, with careful that if we only check whentosave all 8 iterations, number of iterations must be well set at the begining.This is done by adding a (iter&7) in the while statement preceeding then uncompressed calculation. */ /*F. : This is from then lim factor that depends all periodicity check spped : the bigger it is, the faster we can detect periodicity, but the bigger it is, the more we can introduce errors. I suggest a value of (maxx-minx)/(double)getmaxx for a classic Mandelbrot Set, and maybe a lesser value for an extra power Mandelbrot. But this should be calculated outter from here (ie each frame, for example), to avoid new calculs */ #ifdef PERI #define PCHECK (abs_less_than(r1 - zre, cfractalc.periodicity_limit) && abs_less_than(s1 - zim, cfractalc.periodicity_limit)) #ifndef UNCOMPRESS #ifdef SMOOTHMODE static unsigned int FUNCTYPE SPERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE SPERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #else static unsigned int FUNCTYPE PERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE PERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #endif { register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ , iter1 = 8; register number_t r1, s1; int whensavenew, whenincsave; #ifdef RPIP register number_t rp, ip; #endif #ifdef SMOOTHMODE number_t szmag = 0; #endif VARIABLES; INIT; if (PRETEST) iter = 0; else { #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif I386HACK; if (iter < iter1) iter1 = iter, iter = 8; /*H. : do first few iterations w/o checking */ if (BTEST && iter1) { FORMULALOOP(iter1); } /* while (BTEST && iter1) { SAVEZMAG; FORMULA; iter1--; } */ if (iter1) { if (iter >= 8) iter -= 8 - iter1; goto end; } if (iter <= 8) { iter = iter1; } else { iter -= 8; r1 = zre; s1 = zim; whensavenew = 3; /*You should adapt theese values */ /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */ whenincsave = 10; /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is quite slow before going in a periodic loop. So, we should start checking periodicity only after some times */ while (BTEST && iter) { SAVEZMAG; FORMULA; if ((iter & whensavenew) == 0) { /*F. : changed % to & */ r1 = zre; s1 = zim; whenincsave--; if (!whenincsave) { whensavenew = ((whensavenew + 1) << 1) - 1; /*F. : Changed to define a new AND mask */ whenincsave = 10; } } else { if (PCHECK) { PERIINOUTPUT(); } } iter--; } } } end: #ifdef SMOOTHMODE if (iter) SMOOTHOUTPUT(); POSTCALC; iter = cfractalc.maxiter - iter; INOUTPUT(); #else POSTCALC; iter = cfractalc.maxiter - iter; OUTPUT(); #endif } #else /*F. : UNCOMPRESSed version. Note that whensavenew+1 should be a multiple of 8, else periodicity won't be able to detect anything. */ /*F. : this macros definitions are really strange, but after a while, it's good */ #ifdef SMOOTHMODE static unsigned int FUNCTYPE SPERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE SPERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #else static unsigned int FUNCTYPE PERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) CONSTF REGISTERS(3); REGISTERS(3) static unsigned int FUNCTYPE PERI(register number_t zre, register number_t zim, register number_t pre, register number_t pim) #endif { register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ; register number_t r1 = zre, s1 = zim; number_t szre = 0, szim = 0; /*F. : Didn't declared register, cause they are few used */ unsigned int whensavenew, whenincsave; #ifdef RPIP register number_t rp = 0, ip; #endif #ifdef SMOOTHMODE number_t szmag = 0; #endif SAVEVARIABLES VARIABLES; INIT; if (PRETEST) iter = 0; else { if (cfractalc.maxiter <= 16) { I386HACK1; /*I386HACK; */ #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif /*F. : Added iter&7 to be sure we'll be on a 8 multiple */ if (BTEST && iter) { FORMULALOOP(iter); } /* while (BTEST && iter) { SAVEZMAG FORMULA; iter--; } */ } else { whensavenew = 7; /*You should adapt theese values */ /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */ whenincsave = 10; #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is quite slow before going in a periodic loop. So, we should start checking periodicity only after some times */ I386HACK1; /*I386HACK; */ iter = 8 + (cfractalc.maxiter & 7); while (BTEST && iter) { /*F. : Added iter&7 to be sure we'll be on a 8 multiple */ SAVEZMAG FORMULA; iter--; } if (BTEST) { /*F. : BTEST is calculed two times here, isn't it ? */ /*H. : No gcc is clever and adds test to the end :) */ iter = (cfractalc.maxiter - 8) & (~7); do { szre = zre, szim = zim; SAVE; SAVEZMAG /*I386HACK; */ I386HACK1; FORMULA; /*F. : Calculate one time */ if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; FORMULA; if (PCHECK) goto periodicity; iter -= 8; /*F. : We only test this now, as it can't be true before */ if ((iter & whensavenew) == 0) { /*F. : changed % to & */ r1 = zre, s1 = zim; /*F. : Save new values */ whenincsave--; if (!whenincsave) { whensavenew = ((whensavenew + 1) << 1) - 1; /*F. : Changed to define a new AND mask */ whenincsave = 10; /*F. : Start back */ } } } while (BTEST && iter); if (!BTEST) { /*we got out of bounds */ iter += 8; /*restore saved possition */ RESTORE; zre = szre; zim = szim; #ifdef RPIP rp = zre * zre; ip = zim * zim; #endif I386HACK1; /*I386HACK; */ FORMULALOOP(iter); /* do { SAVEZMAG FORMULA; iter--; } while (BTEST && iter); */ } } else iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7); } } #ifdef SMOOTHMODE if (iter) SMOOTHOUTPUT(); POSTCALC; iter = cfractalc.maxiter - iter; INOUTPUT(); #else POSTCALC; iter = cfractalc.maxiter - iter; OUTPUT(); #endif periodicity: PERIINOUTPUT(); } /*else uncompress */ #endif /*endif PERI */ #undef PCHECK #endif #ifndef SMOOTHMODE #ifdef JULIA static void JULIA(struct image *image, register number_t pre, register number_t pim) { int i, i1, i2, j, x, y; unsigned char iter, itmp2, itmp; number_t rp = 0, ip = 0; register number_t zre, zim, im, xdelta, ydelta, range, rangep; number_t xstep, ystep; unsigned char *queue[QMAX]; unsigned char **qptr; unsigned char *addr, **addr1 = image->currlines; #ifdef STATISTICS int guessed = 0, unguessed = 0, iters = 0; #endif VARIABLES; range = (number_t) RANGE; rangep = range * range; xdelta = image->width / (RMAX - RMIN); ydelta = image->height / (IMAX - IMIN); xstep = (RMAX - RMIN) / image->width; ystep = (IMAX - IMIN) / image->height; init_julia(image, rangep, range, xdelta, ystep); for (i2 = 0; i2 < 2; i2++) for (i1 = 0; i1 < image->height; i1++) { if (i1 % 2) i = image->height / 2 - i1 / 2; else i = image->height / 2 + i1 / 2 + 1; if (i >= image->height) continue; im = IMIN + (i + 0.5) * ystep; for (j = (i + i2) & 1; j < image->width; j += 2) { STAT(total2++); addr = addr1[i] + j; if (*addr != NOT_CALCULATED) continue; x = j; y = i; if (y > 0 && y < image->height - 1 && *(addr + 1) && x > 0 && x < image->width - 1) { if ((iter = *(addr + 1)) != NOT_CALCULATED && iter == *(addr - 1) && iter == addr1[y - 1][x] && iter == addr1[y + 1][x]) { *addr = *(addr + 1); continue; } } zim = im; zre = RMIN + (j + 0.5) * xstep; iter = (unsigned char) 0; qptr = queue; ip = (zim * zim); rp = (zre * zre); INIT; while (1) { if (*addr != NOT_CALCULATED #ifdef SAG && (*addr == INPROCESS || (*addr != (unsigned char) 1 && (itmp2 = *(addr + 1)) != NOT_CALCULATED && ((itmp2 != (itmp = *(addr - 1)) && itmp != NOT_CALCULATED) || (itmp2 != (itmp = *((addr1[y + 1]) + x)) && itmp != NOT_CALCULATED) || (itmp2 != (itmp = *((addr1[y - 1]) + x)) && itmp != NOT_CALCULATED)))) #endif ) { if (*addr == INPROCESS || *addr == INSET) { *qptr = addr; qptr++; STAT(guessed++); goto inset; } STAT(guessed++); iter = *addr; goto outset; } #ifdef STATISTICS if (*addr != NOT_CALCULATED) unguessed++; #endif if (*addr != INPROCESS) { *qptr = addr; qptr++; *addr = INPROCESS; if (qptr >= queue + QMAX) goto inset; } STAT(iters++); FORMULA; ip = (zim * zim); rp = (zre * zre); if (greater_than(rp + ip, RANGE) || !(BTEST)) goto outset; x = (int) ((zre - RMIN) * xdelta); y = (int) ((zim - IMIN) * ydelta); addr = addr1[y] + x; if ((itmp = *(addr + 1)) != NOT_CALCULATED && itmp == *(addr - 1) && itmp == addr1[y - 1][x] && itmp == addr1[y + 1][x]) { *addr = *(addr + 1); } } inset: while (qptr > queue) { qptr--; **qptr = INSET; } continue; outset: y = image->palette->size; while (qptr > queue) { qptr--; iter++; if ((int) iter >= y) iter = (unsigned char) 1; **qptr = iter; } } } #ifdef STATISTICS printf("guessed %i, unguessed %i, iterations %i\n", guessed, unguessed, iters); guessed2 += guessed; unguessed2 += unguessed; iters2 += iters; #endif } #endif #endif #undef FORMULALOOP #undef PCHECK #undef I386HACK #undef I386HACK1 #undef SAVEZMAG #ifndef SMOOTHMODE #ifdef SMOOTH #define SMOOTHMODE #include "docalc.c" #endif #endif /*cleanup for next formula */ #undef NSFORMULALOOP #undef SFORMULALOOP #undef PRESMOOTH #undef SMOOTH #undef SMOOTHMODE #undef RANGE #undef JULIA #undef PERI #undef SPERI #undef INIT #undef VARIABLES #undef PRETEST #undef BTEST #undef FORMULA #undef CALC #undef SCALC #undef RPIP #undef POSTCALC #undef UNCOMPRESS #undef SAVE #undef SAVEVARIABLES #undef RESTORE #undef USEHACKS #undef UFORMULA #undef UEND