/* * XaoS, a fast portable realtime fractal zoomer * Copyright (C) 1996,1997 by * * Jan Hubicka (hubicka@paru.cas.cz) * Thomas Marsh (tmarsh@austin.ibm.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*#define STATISTICS */ #include #include #include #include #ifdef _plan9_ #include #include #include #else #include #ifndef _MAC #ifndef NO_MALLOC_H #include #endif #endif #ifndef _plan9_ #include #include #include #endif #endif #ifdef __EMX__ #include #include #endif #include #include #include #include "../include/timers.h" #ifdef __GNUC__ #ifdef __i386__ #ifndef PC_64 #include #endif #endif #endif #ifdef __alpha__ #ifdef __linux__ #include #endif #endif #ifndef M_PI #define M_PI 3.1415 #endif #include struct symetryinfo2 cursymetry; struct palette cpalette; struct image cimage; struct fractal_context cfractalc; struct formula cformula; static symetry2 sym_lines[100]; static void precalculate_rotation(fractal_context * c) { c->sin = sin((c->angle) * M_PI / 180); c->cos = cos((c->angle) * M_PI / 180); } static void recalc_view(fractal_context * c) { number_t xs = c->s.rr, ys = c->s.ri * c->windowwidth / c->windowheight, xc = c->s.cr, yc = c->s.ci, size; precalculate_rotation(c); rotate(*c, xc, yc); /*assert(c->s.rr >= 0); assert(c->s.ri >= 0); */ xs = myabs(xs); /*do not crash in owerflowing cases */ ys = myabs(ys); if (xs > ys) size = xs; else size = ys; c->rs.nc = xc - size / 2; c->rs.mc = xc + size / 2; c->rs.ni = yc - size * c->windowheight / c->windowwidth / 2; c->rs.mi = yc + size * c->windowheight / c->windowwidth / 2; if (c->rs.nc > c->rs.mc) xc = c->rs.nc, c->rs.nc = c->rs.mc, c->rs.mc = xc; if (c->rs.ni > c->rs.mi) xc = c->rs.ni, c->rs.ni = c->rs.mi, c->rs.mi = xc; } static void set_view(fractal_context * c, CONST vinfo * s) { c->s = *s; recalc_view(c); } /*FIXME most of this code is obsolette */ static void /*INLINE */ combine_methods(void) { #ifdef __UNDEFINED__ int i, j; #endif int angle = (int) cfractalc.angle; CONST struct symetryinfo *s1 = cfractalc.currentformula->out + cfractalc.coloringmode, *s2 = cfractalc.currentformula->in + cfractalc.incoloringmode; if (angle < 0) { angle = 360 - ((-angle) % 360); } else angle %= 360; if (cfractalc.mandelbrot != cfractalc.currentformula->mandelbrot || cfractalc.bre || cfractalc.bim) { cursymetry.xsym = (number_t) INT_MAX; cursymetry.ysym = (number_t) INT_MAX; cursymetry.nsymetries = 0; return; } #ifdef __UNDEFINED__ cursymetry.xmul = cimage.width / (cfractalc.rs.mc - cfractalc.rs.nc); cursymetry.ymul = cimage.height / (cfractalc.rs.mi - cfractalc.rs.ni); cursymetry.xdist = (cfractalc.rs.mc - cfractalc.rs.nc) / cimage.width / 6; cursymetry.ydist = (cfractalc.rs.mi - cfractalc.rs.ni) / cimage.height / 6; #endif if (s1->xsym == s2->xsym) cursymetry.xsym = s1->xsym; else cursymetry.xsym = (number_t) INT_MAX; if (s1->ysym == s2->ysym) cursymetry.ysym = s1->ysym; else cursymetry.ysym = (number_t) INT_MAX; switch (cfractalc.plane) { case P_PARABOL: cursymetry.xsym = (number_t) INT_MAX; break; case P_LAMBDA: if (cursymetry.xsym == 0 && cursymetry.ysym == 0) cursymetry.xsym = (number_t) 1; else cursymetry.xsym = (number_t) INT_MAX; break; case P_INVLAMBDA: cursymetry.xsym = (number_t) INT_MAX; break; case P_TRANLAMBDA: if (cursymetry.xsym != 0 || cursymetry.ysym != 0) cursymetry.xsym = (number_t) INT_MAX; break; case P_MEREBERG: cursymetry.xsym = (number_t) INT_MAX; break; } cursymetry.symetry = sym_lines; cursymetry.nsymetries = 0; if ((number_t) angle == cfractalc.angle) { switch (angle) { case 0: break; case 180: cursymetry.xsym = -cursymetry.xsym; cursymetry.ysym = -cursymetry.ysym; break; case 90: { number_t tmp = cursymetry.xsym; cursymetry.xsym = -cursymetry.ysym; cursymetry.ysym = tmp; } break; case 210: { number_t tmp = cursymetry.xsym; cursymetry.xsym = cursymetry.ysym; cursymetry.ysym = -tmp; } break; default: cursymetry.xsym = (number_t) INT_MAX; cursymetry.ysym = (number_t) INT_MAX; } } else { cursymetry.xsym = (number_t) INT_MAX; cursymetry.ysym = (number_t) INT_MAX; } if (cursymetry.xsym == -(number_t) INT_MAX) cursymetry.xsym = (number_t) INT_MAX; if (cursymetry.ysym == -(number_t) INT_MAX) cursymetry.ysym = (number_t) INT_MAX; } void update_view(fractal_context * context) { set_view(context, &context->s); } void set_fractalc(fractal_context * context, struct image *img) { update_view(context); precalculate_rotation(context); cfractalc = *context; /*its better to copy often accesed data into fixed memory locations */ cpalette = *img->palette; cimage = *img; cformula = *context->currentformula; if (cfractalc.maxiter < 1) cfractalc.maxiter = 1; if (cfractalc.bailout < 0) cfractalc.bailout = 0; if (cfractalc.periodicity) { if (!cformula.hasperiodicity || cfractalc.incoloringmode || !cfractalc.mandelbrot) cfractalc.periodicity = 0; else if (!cfractalc.plane) cfractalc.periodicity_limit = (context->rs.mc - context->rs.nc) / (double) img->width; else { int x, y; number_t xstep = ((context->rs.mc - context->rs.nc) / (double) img->width); number_t ystep = ((context->rs.mc - context->rs.nc) / (double) img->height); number_t xstep2 = ((context->rs.mc - context->rs.nc) / 5); number_t ystep2 = ((context->rs.mc - context->rs.nc) / 5); for (x = 0; x < 5; x++) for (y = 0; y < 5; y++) { number_t x1 = context->rs.mc + xstep2 * x; number_t y1 = context->rs.mi + ystep2 * y; number_t x2 = context->rs.mc + xstep2 * x + xstep; number_t y2 = context->rs.mi + ystep2 * y + ystep; recalculate(cfractalc.plane, &x1, &y1); recalculate(cfractalc.plane, &x2, &y2); x1 = myabs(x2 - x1); y1 = myabs(y2 - y1); if (x == y && x == 0) cfractalc.periodicity_limit = x1; if (cfractalc.periodicity > x1) cfractalc.periodicity_limit = x1; if (cfractalc.periodicity > y1) cfractalc.periodicity_limit = y1; } } } combine_methods(); if (cursymetry.xsym == (number_t) INT_MAX) cursymetry.xsym = cfractalc.rs.mc + INT_MAX; if (cursymetry.ysym == (number_t) INT_MAX) cursymetry.ysym = cfractalc.rs.mi + INT_MAX; #ifndef SLOWFUNCPTR if (cfractalc.coloringmode == 9 && cformula.smooth_calculate != NULL && (cpalette. type & (TRUECOLOR | TRUECOLOR16 | TRUECOLOR24 | GRAYSCALE | LARGEITER))) { cfractalc.calculate[0] = cformula.smooth_calculate; if (cformula.smooth_calculate_periodicity && cfractalc.periodicity) cfractalc.calculate[1] = cformula.smooth_calculate_periodicity; else cfractalc.calculate[1] = cformula.smooth_calculate; } else { cfractalc.calculate[0] = cformula.calculate; if (cformula.calculate_periodicity && cfractalc.periodicity) cfractalc.calculate[1] = cformula.calculate_periodicity; else cfractalc.calculate[1] = cformula.calculate; } #endif } void set_formula(fractal_context * c, int num) { assert(num < nformulas); assert(num >= 0); if (num >= nformulas) num = 0; if (c->currentformula != formulas + num) { c->currentformula = formulas + num; c->version++; } if (c->mandelbrot != c->currentformula->mandelbrot) { c->mandelbrot = c->currentformula->mandelbrot; c->version++; } if (c->currentformula->pre != c->pre) { c->pre = c->currentformula->pre; if (!c->mandelbrot) c->version++; } if (c->currentformula->pim != c->pim) { c->pim = c->currentformula->pim; if (!c->mandelbrot) c->version++; } if (c->angle) { c->angle = 0; c->version++; } if (c->s.cr != c->currentformula->v.cr || c->s.ci != c->currentformula->v.ci || c->s.rr != c->currentformula->v.rr || c->s.ri != c->currentformula->v.ri) { c->s = c->currentformula->v; c->version++; } if (c->bre && c->bim) { c->bre = c->bim = 0; if (c->mandelbrot) c->version++; } } void fractalc_resize_to(fractal_context * c, float wi, float he) { c->windowwidth = wi; c->windowheight = he; recalc_view(c); return; } fractal_context *make_fractalc(CONST int formula, float wi, float he) { fractal_context *new_ctxt; #ifndef __BEOS__ #ifdef __GNUC__ #ifdef __i386__ #ifndef NOASSEMBLY _control87(PC_64 | MCW_EM | MCW_RC, MCW_PC | MCW_EM | MCW_RC); #endif #endif #endif #endif #ifdef __alpha__ #ifdef __linux__ extern void ieee_set_fp_control(unsigned long); /* ieee_set_fp_control(IEEE_TRAP_ENABLE_INV); */ ieee_set_fp_control(0UL); /* ignore everything possible */ #endif #endif #ifdef _plan9_ { unsigned long fcr = 0; /*getfcr(); */ fcr |= FPRNR | FPPEXT; /*fcr &= ~(FPINEX | FPOVFL | FPUNFL | FPZDIV); */ setfcr(fcr); } #endif new_ctxt = (fractal_context *) calloc(1, sizeof(fractal_context)); if (new_ctxt == NULL) return 0; new_ctxt->windowwidth = wi; new_ctxt->periodicity = 1; new_ctxt->windowheight = he; new_ctxt->maxiter = DEFAULT_MAX_ITER; new_ctxt->bailout = DEFAULT_BAILOUT; new_ctxt->coloringmode = 0; new_ctxt->intcolor = 0; new_ctxt->outtcolor = 0; new_ctxt->slowmode = 0; new_ctxt->range = 3; new_ctxt->angle = 0; set_formula(new_ctxt, formula); return (new_ctxt); } void free_fractalc(fractal_context * c) { free(c); } #ifdef NOASSEMBLY #define rdtsc() 0 #else #define rdtsc() ({unsigned long time; asm __volatile__ ("rdtsc":"=a"(time)); time; }) #endif void speed_test(fractal_context * c, struct image *img) { //unsigned int sum; tl_timer *t; int time; unsigned int i; set_fractalc(c, img); t = tl_create_timer(); cfractalc.maxiter = 100; #ifdef SLOWFUNCPTR i = calculateswitch(0.0, 0.0, 0.0, 0.0, 0); #else cfractalc.currentformula->calculate(0.0, 0.0, 0.0, 0.0); if (cfractalc.currentformula->calculate_periodicity != NULL) cfractalc.currentformula->calculate_periodicity(0.0, 0.0, 0.0, 0.0); if (cfractalc.currentformula->smooth_calculate != NULL) cfractalc.currentformula->smooth_calculate(0.0, 0.0, 0.0, 0.0); if (cfractalc.currentformula->smooth_calculate_periodicity != NULL) cfractalc.currentformula->smooth_calculate_periodicity(0.0, 0.0, 0.0, 0.0); #endif cfractalc.maxiter = 20000000; tl_update_time(); tl_reset_timer(t); /*sum = rdtsc (); */ #ifdef SLOWFUNCPTR i = calculateswitch(0.0, 0.0, 0.0, 0.0, 0); #else i = cfractalc.currentformula->calculate(0.0, 0.0, 0.0, 0.0); #endif /*sum -= rdtsc (); printf ("%f\n", (double) (-sum) / cfractalc.maxiter); */ tl_update_time(); time = tl_lookup_timer(t); x_message("Result:%i Formulaname:%s Time:%i Mloops per sec:%.2f", (int) i, cfractalc.currentformula->name[0], time, cfractalc.maxiter / (double) time); #ifndef SLOWFUNCPTR if (cfractalc.currentformula->smooth_calculate != NULL) { tl_update_time(); tl_reset_timer(t); i = cfractalc.currentformula->smooth_calculate(0.0, 0.0, 0.0, 0.0); tl_update_time(); time = tl_lookup_timer(t); x_message("Result:%i Formulaname:%s Time:%i Mloops per sec:%.2f", (int) i, cfractalc.currentformula->name[0], time, cfractalc.maxiter / (double) time); } #endif tl_free_timer(t); }