From 1030dc837b10a03a02a85d5504cbeec168ce49e2 Mon Sep 17 00:00:00 2001 From: Bernie Innocenti Date: Mon, 03 May 2010 21:53:47 +0000 Subject: Import XaoS r489 (trunk after version 3.5) --- (limited to 'src/engine') diff --git a/src/engine/3d.c b/src/engine/3d.c new file mode 100644 index 0000000..517d3db --- /dev/null +++ b/src/engine/3d.c @@ -0,0 +1,240 @@ +#ifndef _plan9_ +#include +#ifndef NO_MALLOC_H +#include +#endif +#include /*for NULL */ +#include +#else +#include +#include +#include +#endif +#define SLARGEITER +#include +#include + +struct threeddata { + struct palette *pal; + struct palette *savedpalette; + unsigned int *pixels; + unsigned int maxiter; + unsigned int height; + unsigned int colheight; + unsigned int midcolor; + unsigned int darkcolor; + unsigned int stereogrammode; +}; + +#define spixel_t pixel16_t +#include +#define do_3d do_3d8 +#define convert_3d convert_3d8 +#define convertup_3d convertup_3d8 +#include "3dd.c" + +#include +#define do_3d do_3d32 +#define convert_3d convert_3d32 +#define convertup_3d convertup_3d32 +#include "3dd.c" + +#include +#define do_3d do_3d24 +#define convert_3d convert_3d24 +#define convertup_3d convertup_3d24 +#include "3dd.c" + +#include +#define do_3d do_3d16 +#define convert_3d convert_3d16 +#define convertup_3d convertup_3d16 +#include "3dd.c" + +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags &= ~IMAGEDATA; + r->supportedmask = MASK1BPP | MASK3BPP | MASK2BPP | MASK4BPP; + return (f->next->action->requirement(f->next, r)); +} + +extern CONST struct filteraction stereogram_filter; +static int initialize(struct filter *f, struct initdata *i) +{ + struct threeddata *d = (struct threeddata *) f->data; + struct filter *f1 = f; + inhermisc(f, i); + d->stereogrammode = 0; + while (f1) { + if (f1->action == &stereogram_filter) + d->stereogrammode = 1; + f1 = f1->next; + } + d->maxiter = -1; + d->height = i->image->height / 3; + if (d->pal != NULL) + destroypalette(d->pal); + d->pal = + createpalette(0, 65536, LARGEITER, 0, 65536, NULL, NULL, NULL, + NULL, NULL); + /*in/out coloring modes looks better in iter modes. This also saves some + memory in truecolor. */ + if (i->image->palette->type == LARGEITER + || i->image->palette->type == SMALLITER) { + } else { + if (d->savedpalette == NULL) + d->savedpalette = clonepalette(i->image->palette); + + mkgraypalette(i->image->palette); + } + if (d->pixels != NULL) { + free(d->pixels); + d->pixels = NULL; + } + if (!inherimage + (f, i, TOUCHIMAGE | NEWIMAGE, + i->image->width + 6 + (i->image->height + d->height + 6) / 2, + i->image->height + d->height + 6, d->pal, i->image->pixelwidth, + i->image->pixelheight * 2)) + return 0; + setfractalpalette(f, d->savedpalette); + fractalc_resize_to(f->fractalc, + f->childimage->pixelwidth * f->childimage->width, + f->childimage->pixelheight * f->childimage->height); + f->fractalc->version++; + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct threeddata *d = calloc(sizeof(*d), 1); + f->data = d; + f->name = "3d"; + return (f); +} + +static void destroyinstance(struct filter *f) +{ + struct threeddata *d = (struct threeddata *) f->data; + if (d->pal != NULL) + destroypalette((struct palette *) d->pal); + if (d->savedpalette != NULL) + destroypalette(d->savedpalette); + if (d->pixels) { + d->pixels = 0; + free(d->pixels); + } + free(d); + destroyinheredimage(f); + free(f); +} + +static int doit(struct filter *f, int flags, int time) +{ + int val; + int size = f->childimage->palette->type == SMALLITER ? 240 : 65520; + struct threeddata *d = (struct threeddata *) f->data; + if (f->image->palette->size < size) + size = f->image->palette->size; + + /* Update logarithmic scale palette. */ + if (f->fractalc->maxiter != d->maxiter) { + unsigned int i; + int palsize = f->fractalc->maxiter; + if (palsize >= 65536) + palsize = 65535; + d->colheight = d->height * (64 + 32) / 64; + d->midcolor = d->height * 60 / 100; + d->darkcolor = d->height * 30 / 100; + d->pal->size = palsize; + for (i = 0; i < (unsigned int) palsize; i++) { + unsigned int y; + y = (log10(1 + 10.0 * (i ? i : palsize) / palsize)) * + d->colheight / 9.0 * 16.0 / 2.0; + /*y = (i ? i : palsize) * d->colheight / 9.0 / 2.0 * 16.0 / palsize; */ + if (y != d->pal->pixels[i]) + f->fractalc->version++; + d->pal->pixels[i] = y; + } + d->maxiter = f->fractalc->maxiter; + if (d->pixels) + free(d->pixels); + i = 0; + if (d->stereogrammode) { + d->pixels = + malloc((f->childimage->height) * sizeof(*d->pixels)); + for (i = 0; i < (unsigned int) f->childimage->height; i++) { + d->pixels[i] = + (f->childimage->height - + i) * 255 / f->childimage->height; + } + } else { + d->pixels = malloc((d->colheight + 5) * sizeof(*d->pixels)); + for (; i < d->colheight; i++) { + int c = i * (f->image->palette->size) / d->colheight; + if (c > f->image->palette->size - 1) + c = f->image->palette->size - 1; + d->pixels[i] = f->image->palette->pixels[c]; + } + d->pixels[i] = f->image->palette->pixels[0]; + } + } + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + drivercall(*f->image, + xth_function(do_3d8, f, f->image->width), + xth_function(do_3d16, f, f->image->width), + xth_function(do_3d24, f, f->image->width), + xth_function(do_3d32, f, f->image->width)); + xth_sync(); + return val; +} + +static void myremove(struct filter *f) +{ + struct threeddata *d = (struct threeddata *) f->data; + fractalc_resize_to(f->fractalc, f->image->width * f->image->pixelwidth, + f->image->height * f->image->pixelheight); + if (d->savedpalette != NULL) { + restorepalette(f->image->palette, d->savedpalette); + destroypalette(d->savedpalette); + d->savedpalette = NULL; + } + +} + +static void convertup(struct filter *f, int *x, int *y) +{ + drivercall(*f->image, + convertup_3d8(f, x, y), + convertup_3d16(f, x, y), + convertup_3d24(f, x, y), convertup_3d32(f, x, y)); + f->next->action->convertup(f->next, x, y); +} + +static void convertdown(struct filter *f, int *x, int *y) +{ + drivercall(*f->image, + convert_3d8(f, x, y), + convert_3d16(f, x, y), + convert_3d24(f, x, y), convert_3d32(f, x, y)); + if (f->previous != NULL) + f->previous->action->convertdown(f->previous, x, y); +} + +CONST struct filteraction threed_filter = { + "Pseudo 3d", + "threed", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertup, + convertdown, + myremove +}; diff --git a/src/engine/3dd.c b/src/engine/3dd.c new file mode 100644 index 0000000..f6a92fb --- /dev/null +++ b/src/engine/3dd.c @@ -0,0 +1,200 @@ +#ifndef UNSUPPORTED +static void convert_3d(struct filter *f, int *x1, int *y1) +{ + struct threeddata *data = (struct threeddata *) f->data; + int y; + int x = *x1; + unsigned int inp; + unsigned int height = data->height; + register CONST spixel_t *input; + if (x >= f->childimage->width - 5 || x < 0 + || *y1 > f->childimage->height) { + *x1 += *y1 / 2; + return; + } + if (x < 0) + x = 0; + for (y = f->childimage->height - 3; y >= 0; y--) { + int d; + input = ((spixel_t *) f->childimage->currlines[y] + y / 2); + inp = (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + input = ((spixel_t *) f->childimage->currlines[y + 1] + y / 2); + inp += (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + input = ((spixel_t *) f->childimage->currlines[y + 2] + y / 2); + inp += (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + d = y - (inp / 16 > height ? height : inp / 16); + if (d <= *y1) { + *y1 = y; + *x1 = x + y / 2; + return; + } + } + *x1 += *y1 / 2; + return; +} + +static void convertup_3d(struct filter *f, int *x1, int *y1) +{ + struct threeddata *data = (struct threeddata *) f->data; + int y = *y1; + int x = *x1; + unsigned int inp; + unsigned int height = data->height; + register CONST spixel_t *input; + if (x >= f->childimage->width - 5) + x = f->childimage->width - 6; + if (y >= f->childimage->height - 3) + y = f->childimage->height - 3; + if (x < 0) + x = 0; + if (y < 0) + y = 0; + input = ((spixel_t *) f->childimage->currlines[y] + y / 2); + inp = (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + input = ((spixel_t *) f->childimage->currlines[y + 1] + y / 2); + inp += (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + input = ((spixel_t *) f->childimage->currlines[y + 2] + y / 2); + inp += (input[x] + input[x + 1] + input[x + 2] + + input[x + 3] + input[x + 4] + input[x + 5]); + *x1 -= *y1 / 2; + *y1 = y - (inp / 16 > height ? height : inp / 16); +} + +static void do_3d(void *dataptr, struct taskinfo *task, int r1, int r2) +{ + struct filter *RESTRICT f = (struct filter *) dataptr; + unsigned int y; + int maxinp = 0; + unsigned int x; + unsigned int end; + unsigned int sum; + spixel_t CONST *RESTRICT input; + unsigned int *RESTRICT lengths; + unsigned int *RESTRICT sums; + unsigned int *RESTRICT relsums; + struct threeddata *data = (struct threeddata *) f->data; + + + /* Copy to local variables to improve cse and memory references. */ + unsigned int height = data->height; + unsigned int stereogrammode = data->stereogrammode; + unsigned int colheight = data->colheight; + unsigned int midcolor = data->midcolor; + unsigned int darkcolor = data->darkcolor; + CONST unsigned int *RESTRICT pixels = data->pixels; + cpixel_t *RESTRICT * RESTRICT currlines = + (cpixel_t * RESTRICT * RESTRICT) f->image->currlines; + struct inp { + int max; + unsigned int down; + } *inpdata; + +#ifdef HAVE_ALLOCA1 + lengths = + (unsigned int *) alloca(sizeof(unsigned int) * f->image->width); + inpdata = + (struct inp *) alloca(sizeof(struct inp) * (f->image->width + 2)); + sums = + (unsigned int *) alloca(sizeof(unsigned int) * + (f->image->width + 2) * 2); +#else + lengths = + (unsigned int *) malloc(sizeof(unsigned int) * f->image->width); + inpdata = + (struct inp *) malloc(sizeof(struct inp) * (f->image->width + 2)); + sums = + (unsigned int *) malloc(sizeof(unsigned int) * + (f->image->width + 2) * 2); +#endif + for (x = 0; x < (unsigned int) f->image->width; x++) + lengths[x] = f->image->height - 1, + sums[x * 2 + 0] = 0, sums[x * 2 + 1] = 0, inpdata[x].max = 0; + sums[x * 2 + 0] = 0, sums[x * 2 + 1] = 0, inpdata[x].max = 0; + inpdata[x + 1].max = 0; + end = r2; + for (y = f->childimage->height - 2; y > 0;) { + y--; + input = ((spixel_t *) f->childimage->currlines[y] + y / 2); + x = r1; + relsums = sums + (y & 1); + + /* Fix boundary cases. */ + /*relsums[0] = relsums[1]; + relsums[end*2-1] = relsums[end*2-2]; */ + inpdata[end + 1] = inpdata[end] = inpdata[end - 1]; + sum = + input[x] + input[x + 1] + input[x + 2] + input[x + 3] + + input[x + 4] + input[x + 5]; + + while (x < end) { + unsigned int inp; + unsigned int d; + + /* Average pixel values of 5*3 square to get nicer shapes. */ + sum += input[x + 6] - input[x]; + inp = sum + sums[x * 2 + 1] + sums[x * 2]; + relsums[x * 2] = sum; + inpdata[x].down = inp; + + /* Calculate shades. */ + maxinp = inpdata[x + 2].max; + if ((int) inp > maxinp) + inpdata[x].max = inp - 32; + else + inpdata[x].max = maxinp - 32; + + /* caluclate top of mountain. */ + d = inp / 16; + d = y - (d > height ? height : d); + + /* Underflow */ + if (d > 65535U) + d = 0; + if (d < lengths[x]) { + int y1; + unsigned int color; + if (stereogrammode) + color = pixels[y]; + else if (inp / 16 > height) + /*Red thinks on the top. */ + color = + pixels[inp / 16 >= + colheight ? colheight : inp / 16]; + else { + int c; + /* Simple shading model. + Depends only on the preceding voxel. */ + + c = ((int) inpdata[x + 2].down - (int) inp) / 8; + + /* Get shades. */ + color = + ((int) inp > maxinp ? midcolor : darkcolor) - c; + color = + pixels[color < + 65535 ? (color < + height ? color : height) : 0]; + } + for (y1 = lengths[x]; y1 >= (int) d; y1--) { + p_setp(currlines[y1], x, color); + } + lengths[x] = d; + } + x++; + } + } +#ifndef HAVE_ALLOCA1 + free(lengths); + free(inpdata); + free(sums); +#endif +} +#endif +#undef do_3d +#undef convert_3d +#undef convertup_3d diff --git a/src/engine/Makefile.in b/src/engine/Makefile.in new file mode 100644 index 0000000..5615ae6 --- /dev/null +++ b/src/engine/Makefile.in @@ -0,0 +1,70 @@ +CC = @CC@ +CFLAGS = @CFLAGS@ +LIBS = @LIBS@ -lm +LFLAGS = @LDFLAGS@ +AR = @AR@ +RANLIB = @RANLIB@ + +SRCS = formulas.c \ + fractal.c \ + btrace.c \ + palettef.c \ + emboss.c \ + star.c \ + anti.c \ + dither.c \ + edge.c \ + edge2.c \ + rotate.c \ + zoom.c \ + blur.c \ + interlace.c \ + itersmall.c \ + stereogram.c \ + 3d.c \ + subwindow.c \ + plane.c \ + julia.c \ + i386.c + + +OBJS = $(SRCS:.c=.o) + +TLIB = ../lib/libengine.a + + +all: $(TLIB) + +$(TLIB):$(OBJS) + rm -f $@ + $(AR) rc $@ $(OBJS) + $(RANLIB) $@ + +formulas.o: docalc.c +3d.o: 3dd.c +btrace.o: btraced.c +edge2.o: edge2d.c +palette.o: paletted.c +rotate.o: rotated.c +stereogram.o: stereod.c +star.o: stard.c +zoom.o: zoomd.c + +clean: + rm -f $(TLIB) + rm -f *.[oas] + rm -f *~ + rm -f core + +distclean:clean + rm Makefile + +#dep: +# rm -f .depend +# make .depend +# +#.depend: +# echo '# Program dependencies' >.depend +# gcc -I svgalib $(DEFINES) -MM $(patsubst %.o,%.c,$(OBJS)) >>.depend +# +#include .depend diff --git a/src/engine/anti.c b/src/engine/anti.c new file mode 100644 index 0000000..819d33e --- /dev/null +++ b/src/engine/anti.c @@ -0,0 +1,358 @@ +#include +#ifndef _plan9_ +#ifndef __cplusplus +#include +#endif +#ifndef NO_MALLOC_H +#include +#endif +#include +#include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif +#include +#else +#include +#include +#include +#endif +#include +#include +#include +#include +struct antidata { + int shift; +}; +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->supportedmask = TRUECOLOR24 | TRUECOLOR | TRUECOLOR16 | GRAYSCALE; + return (f->next->action->requirement(f->next, r)); +} + +static int initialize(struct filter *f, struct initdata *i) +{ + struct antidata *s = (struct antidata *) f->data; + if (i->image->width * i->image->height * i->image->bytesperpixel * 2 * + 16 > 15 * 1024 * 1024) { + s->shift = 1; + } else { + s->shift = 2; + } + inhermisc(f, i); + if (!inherimage + (f, i, TOUCHIMAGE | IMAGEDATA, + (int) (((unsigned int) i->image->width) << s->shift), + (int) (((unsigned int) i->image->height) << s->shift), NULL, 0, + 0)) + return 0; + if (i->image == NULL) { + return 0; + } + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct antidata *i = (struct antidata *) calloc(1, sizeof(*i)); + f->childimage = NULL; + f->data = i; + f->name = "Antialiasing"; + return (f); +} + +static void destroyinstance(struct filter *f) +{ + destroyinheredimage(f); + free(f->data); + free(f); +} + +static void antigray(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct antidata *s = (struct antidata *) f->data; + register unsigned char *src; + unsigned char *destend, *dest; + unsigned int ystart, y; + unsigned int xstart; + register unsigned int sum; + unsigned int xstep = (1U << (s->shift)); + int i; + for (i = r1; i < r2; i++) { + dest = (unsigned char *) desti->currlines[i]; + destend = dest + desti->width; + ystart = ((unsigned int) i) << s->shift; + xstart = 0; + for (; dest < destend; dest++) { + if (xstep > 2) { + sum = 0; + for (y = 0; y < 4; y++) { + src = + (unsigned char *) srci->currlines[y + ystart] + + xstart; + sum += (unsigned int) src[0]; + sum += (unsigned int) src[1]; + sum += (unsigned int) src[2]; + sum += (unsigned int) src[3]; + } + sum >>= 4; + } else { + src = (unsigned char *) srci->currlines[ystart] + xstart; + sum = (unsigned int) src[0]; + sum += (unsigned int) src[1]; + src = + (unsigned char *) srci->currlines[ystart + 1] + xstart; + sum += (unsigned int) src[0]; + sum += (unsigned int) src[1]; + sum >>= 2; + } + *dest = (pixel8_t) sum; + xstart += xstep; + } + } +} + +#ifdef STRUECOLOR24 +static void anti24(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct antidata *s = (struct antidata *) f->data; + register unsigned char *src; + unsigned char *destend, *dest; + unsigned int ystart, y; + unsigned int xstart; + register unsigned int sum; + unsigned int xstep = ((1U << s->shift) - 1) * 3; + int c = 0; + int i; + if (!srci->palette->info.truec.byteexact) { + x_fatalerror + ("Antialiasing filter:Unsupported colormask! Ask authors to add support for this :)"); + } + for (i = r1; i < r2; i++) { + dest = (unsigned char *) desti->currlines[i]; + destend = dest + desti->width * 3; + ystart = ((unsigned int) i) << s->shift; + xstart = 0; + c = 1; + for (; dest < destend; dest++) { + if (s->shift > 1) { + sum = 0; + for (y = 0; y < 4; y++) { + src = + (unsigned char *) srci->currlines[y + ystart] + + xstart; + sum += (unsigned int) src[0]; + sum += (unsigned int) src[3]; + sum += (unsigned int) src[6]; + sum += (unsigned int) src[9]; + } + sum >>= 4; + } else { + src = (unsigned char *) srci->currlines[ystart] + xstart; + sum = (unsigned int) src[0]; + sum += (unsigned int) src[3]; + src = + (unsigned char *) srci->currlines[ystart + 1] + xstart; + sum += (unsigned int) src[0]; + sum += (unsigned int) src[3]; + sum >>= 2; + } + *dest = (unsigned char) sum; + if (c == 3) + c = 0, xstart += xstep; + c++; + xstart++; + } + } +} +#endif +#ifdef SUPPORT16 +#define MASKR1 ((unsigned int)((31+31744)+(31*65536*32))) +#define MASKR2 ((unsigned int)((31+31744)*(65536/32)+31)) + +#define MASKRH1 (31+31744) +#define MASKRH2 (31*32) +static void anti16(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct antidata *s = (struct antidata *) f->data; + register unsigned int *src; + unsigned short *destend, *dest; + int ystart, y; + int xstart; + register unsigned int sum1 = 0, sum2 = 0, sum; + unsigned int xstep = 1U << (s->shift - 1); + int i; + unsigned int mask1 = + (srci->palette->info.truec. + mask2 | (srci->palette->info.truec.mask1 << 16)) >> 4; + unsigned int mask2 = + srci->palette->info.truec.mask1 | (srci->palette->info.truec. + mask2 << 16); + for (i = r1; i < r2; i++) { + dest = (unsigned short *) desti->currlines[i]; + destend = dest + desti->width; + ystart = ((unsigned int) i) << s->shift; + xstart = 0; + for (; dest < destend; dest++) { + if (xstep > 2) { + sum1 = sum2 = 0; + for (y = 0; y < 4; y++) { + src = + (unsigned int *) srci->currlines[y + ystart] + + xstart; + sum1 += ((unsigned int) src[0] >> 4) & mask1; + sum2 += ((unsigned int) src[0] >> 4) & mask2; + sum1 += (unsigned int) src[1] & mask1; + sum2 += (unsigned int) src[1] & mask2; + } + sum = ((sum1 >> 4) + (sum2 >> 16)) >> 4; + sum1 = (sum2 + (sum1 >> 12)) >> 4; + } else { + src = (unsigned int *) srci->currlines[ystart] + xstart; + sum1 = ((unsigned int) src[0] >> 4) & mask1; + sum2 = (unsigned int) src[0] & mask2; + src = + (unsigned int *) srci->currlines[ystart + 1] + xstart; + sum1 += ((unsigned int) src[0] >> 4) & mask1; + sum2 += (unsigned int) src[0] & mask2; + sum = ((sum1 << 4) + (sum2 >> 16)) >> 2; + sum1 = (sum2 + (sum1 >> 12)) >> 2; + } + *dest = + (sum & srci->palette->info.truec. + mask2) | (sum1 & srci->palette->info.truec.mask1); + xstart += xstep; + } + } +} +#endif + + +#define MASK1 0x00ff00ff +static void anti32(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct antidata *s = (struct antidata *) f->data; + register unsigned int *src; + unsigned int *destend, *dest; + unsigned int ystart, y; + unsigned int xstart; + register unsigned int sum1 = 0, sum2 = 0; + unsigned int xstep = 1U << s->shift; + int i; + if (!srci->palette->info.truec.byteexact) { + x_fatalerror + ("Antialiasing filter:Unsupported colormask2! ask authors to add support for this :)"); + } + for (i = r1; i < r2; i++) { + dest = (unsigned int *) desti->currlines[i]; + destend = dest + desti->width; + ystart = ((unsigned int) i) << s->shift; + xstart = 0; + for (; dest < destend; dest++) { + if (xstep > 2) { + sum1 = sum2 = 0; + for (y = 0; y < 4; y++) { + src = + (unsigned int *) srci->currlines[y + ystart] + + xstart; + sum1 += (unsigned int) src[0] & MASK1; + sum2 += ((unsigned int) src[0] >> 8) & MASK1; + sum1 += (unsigned int) src[1] & MASK1; + sum2 += ((unsigned int) src[1] >> 8) & MASK1; + sum1 += (unsigned int) src[2] & MASK1; + sum2 += ((unsigned int) src[2] >> 8) & MASK1; + sum1 += (unsigned int) src[3] & MASK1; + sum2 += ((unsigned int) src[3] >> 8) & MASK1; + } + sum1 >>= 4; + sum2 >>= 4; + } else { + src = (unsigned int *) srci->currlines[ystart] + xstart; + sum1 = (unsigned int) src[0] & MASK1; + sum2 = ((unsigned int) src[0] >> 8) & MASK1; + sum1 += (unsigned int) src[1] & MASK1; + sum2 += ((unsigned int) src[1] >> 8) & MASK1; + src = + (unsigned int *) srci->currlines[ystart + 1] + xstart; + sum1 += (unsigned int) src[0] & MASK1; + sum2 += ((unsigned int) src[0] >> 8) & MASK1; + sum1 += (unsigned int) src[1] & MASK1; + sum2 += ((unsigned int) src[1] >> 8) & MASK1; + sum1 >>= 2; + sum2 >>= 2; + } + *dest = (sum1 & MASK1) | ((sum2 & MASK1) << 8); + xstart += xstep; + } + } +} + +static int doit(struct filter *f, int flags, int time1) +{ + int val; + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time1); + switch (f->image->palette->type) { + case GRAYSCALE: + xth_function(antigray, f, f->image->height); + break; +#ifdef STRUECOLOR24 + case TRUECOLOR24: + xth_function(anti24, f, f->image->height); + break; +#endif +#ifdef SUPPORT16 + case TRUECOLOR16: + xth_function(anti16, f, f->image->height); + break; +#endif + case TRUECOLOR: + xth_function(anti32, f, f->image->height); + break; + } + xth_sync(); + return val; +} + +static void convertup(struct filter *f, int *x, int *y) +{ + struct antidata *s = (struct antidata *) f->data; + *x >>= s->shift; + *y >>= s->shift; + f->next->action->convertup(f->next, x, y); +} + +static void convertdown(struct filter *f, int *x, int *y) +{ + struct antidata *s = (struct antidata *) f->data; + *x <<= s->shift; + *y <<= s->shift; + f->previous->action->convertdown(f->previous, x, y); +} + + +CONST struct filteraction antialias_filter = { + "Antialiasing", + "anti", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertup, + convertdown, + NULL, +}; diff --git a/src/engine/blur.c b/src/engine/blur.c new file mode 100644 index 0000000..bfef8f3 --- /dev/null +++ b/src/engine/blur.c @@ -0,0 +1,393 @@ +#include +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include +#endif +#include +#include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif +#include +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#define SIZE 64 +#define SIZE2 8 +#define AMOUNT 0.005 +#define DIV 1000.0 +#define MAXFRAMES 800*1000 /*after 800 frames should be OK */ +struct blurdata { + int bckuptime; + int counter; + struct palette *savedpalette, *palette; + unsigned char (*table)[256]; /*Used by blur routines */ + int n; +}; +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags |= IMAGEDATA; + r->supportedmask = + C256 | TRUECOLOR24 | TRUECOLOR | TRUECOLOR16 | GRAYSCALE; + return (f->next->action->requirement(f->next, r)); +} + +static void blur8(struct filter *f) +{ + struct image *desti = f->image; + struct blurdata *s = (struct blurdata *) f->data; + unsigned char (*table)[256] = s->table; + unsigned int i, i1, im, im1, ipl, ii; + if (f->image->palette->type == C256) + for (i = im = 0; i < SIZE; i++, im += 256 - s->n) { + for (i1 = im1 = 0; i1 < SIZE2; + i1++, im1 += s->n * (SIZE / SIZE2)) { + ipl = (im + im1 + 128) >> 8; + ii = i1 * (SIZE / SIZE2); + if (ipl == i && i != ii) { + if (i < ii) + ipl++; + else + ipl--; + } + ii = desti->palette->pixels[i]; + table[i1][ii] = + (unsigned char) desti->palette->pixels[ipl]; + } + } else + for (i = im = desti->palette->start, im *= 256 - s->n; + i < (unsigned int) desti->palette->end; i++, im += 256 - s->n) + { + for (i1 = im1 = desti->palette->start, im1 *= s->n; + i1 < (unsigned int) desti->palette->end; + i1++, im1 += s->n) { + ipl = (im + im1 + 128) >> 8; + if (ipl == i && i != i1) { + if (i < i1) + ipl++; + else + ipl--; + } + table[i1][i] = (unsigned char) ipl; + } + } +} + +static void blurtruecolor(struct filter *f) +{ + struct blurdata *s = (struct blurdata *) f->data; + unsigned int i, i1, im, im1; + unsigned char (*table)[256] = s->table; + for (i = im = 0; i < 256; i++, im += 256 - s->n) { + for (i1 = im1 = 0; i1 < 256; i1++, im1 += s->n) + table[i1][i] = (unsigned char) ((im + im1) >> 8); + } +} + +static void clear_image2(struct image *img) +{ + int i; + int color = img->palette->pixels[0]; + int width = img->width * img->bytesperpixel; + if (!width) + width = (img->width + 7) / 8; + for (i = 0; i < img->height; i++) + memset_long(img->currlines[i], color, (size_t) width); +} + + +static int initialize(struct filter *f, struct initdata *i) +{ + struct blurdata *s = (struct blurdata *) f->data; + unsigned int x; + inhermisc(f, i); + s->counter = 0; + s->palette->size = SIZE2; + for (x = 0; x < SIZE2; x++) + s->palette->pixels[x] = x; + if (datalost(f, i) || i->image->version != f->imageversion) { + s->bckuptime = MAXFRAMES; + s->counter = MAXFRAMES; + if (i->image->palette->type == C256) { + if (s->savedpalette == NULL) + s->savedpalette = clonepalette(i->image->palette); + mkblurpalette(i->image->palette); + } else { + if (s->savedpalette != NULL) { + restorepalette(i->image->palette, s->savedpalette); + destroypalette(s->savedpalette); + s->savedpalette = NULL; + } + } + clear_image2(i->image); + } + if (!inherimage + (f, i, TOUCHIMAGE | IMAGEDATA, 0, 0, + i->image->palette->type == C256 ? s->palette : NULL, 0, 0)) + return 0; + if (f->image->palette->type == C256) { + setfractalpalette(f, s->savedpalette); + } + if (i->image == NULL) { + return 0; + } + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct blurdata *i = (struct blurdata *) calloc(1, sizeof(*i)); + i->savedpalette = NULL; + i->palette = + createpalette(0, 256, SMALLITER, 0, 256, NULL, NULL, NULL, NULL, + NULL); + i->palette->size = SIZE2; + i->palette->end = SIZE2; + i->table = NULL; + f->childimage = NULL; + f->data = i; + f->name = "Motionblur"; + return (f); +} + +static void destroyinstance(struct filter *f) +{ + struct blurdata *i = (struct blurdata *) f->data; + if (i->table != NULL) + free(i->table); + if (i->savedpalette != NULL) + destroypalette(i->savedpalette); + destroypalette(i->palette); + destroyinheredimage(f); + free(f->data); + free(f); +} + +/* An part of blur function that should be done paraely */ +static void blur82(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct blurdata *s = (struct blurdata *) f->data; + unsigned char (*table)[256]; + int i, im; + unsigned char *src, *dest, *srcend; + + im = srci->width; + table = s->table; + for (i = r1; i < r2; i++) { + src = srci->currlines[i]; + srcend = src + im; + dest = desti->currlines[i]; + for (; src < srcend; src++, dest++) { + dest[0] = table[src[0]][dest[0]]; + } + } +} + +#ifdef SUPPORT16 +static void blur16(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct blurdata *s = (struct blurdata *) f->data; + struct truec *info = &srci->palette->info.truec; + unsigned int rmask = info->rmask; + unsigned int gmask = info->gmask; + unsigned int bmask = info->bmask; + unsigned int n = (unsigned int) s->n; + int i; + pixel16_t *src, *dest, *srcend; + for (i = r1; i < r2; i++) { + src = (pixel16_t *) srci->currlines[i]; + srcend = src + srci->width; + dest = (pixel16_t *) desti->currlines[i]; + for (; src < srcend; src++, dest++) { + *dest = interpol(*src, *dest, n, rmask, gmask, bmask); + } + } +} +#endif +#ifdef STRUECOLOR24 +static void blur24(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct blurdata *s = (struct blurdata *) f->data; + unsigned char (*table)[256] = s->table; + unsigned char *src, *dest, *srcend; + int i, im; + im = srci->width * 3; + if (!srci->palette->info.truec.byteexact) { + x_fatalerror + ("Blur filter:unsupported color configuration! Please contact authors."); + } + for (i = r1; i < r2; i++) { + src = srci->currlines[i]; + srcend = src + im; + dest = desti->currlines[i]; + for (; src < srcend; src += 3, dest += 3) { + dest[0] = table[src[0]][dest[0]]; + dest[1] = table[src[1]][dest[1]]; + dest[2] = table[src[2]][dest[2]]; + } + } +} +#endif +static void blur32(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *srci = f->childimage, *desti = f->image; + struct blurdata *s = (struct blurdata *) f->data; + unsigned char (*table)[256] = s->table; + unsigned char *src, *dest, *srcend; + int i, im; + im = srci->width * 4; + if (!srci->palette->info.truec.byteexact) { + x_fatalerror + ("Blur filter:unsupported color configuration! Please contact authors."); + } + for (i = r1; i < r2; i++) { + src = srci->currlines[i]; + srcend = src + im; + dest = desti->currlines[i]; + switch (f->image->palette->info.truec.missingbyte) { + case 3: + for (; src < srcend; src += 4, dest += 4) { + dest[0] = table[src[0]][dest[0]]; + dest[1] = table[src[1]][dest[1]]; + dest[2] = table[src[2]][dest[2]]; + } + break; + case 2: + for (; src < srcend; src += 4, dest += 4) { + dest[0] = table[src[0]][dest[0]]; + dest[1] = table[src[1]][dest[1]]; + dest[3] = table[src[2]][dest[2]]; + } + break; + case 1: + for (; src < srcend; src += 4, dest += 4) { + dest[0] = table[src[0]][dest[0]]; + dest[2] = table[src[1]][dest[1]]; + dest[3] = table[src[2]][dest[2]]; + } + break; + case 0: + for (; src < srcend; src += 4, dest += 4) { + dest[1] = table[src[1]][dest[1]]; + dest[2] = table[src[2]][dest[2]]; + dest[3] = table[src[3]][dest[3]]; + } + break; + default: + for (; src < srcend; src += 4, dest += 4) { + dest[1] = table[src[1]][dest[1]]; + dest[2] = table[src[2]][dest[2]]; + dest[3] = table[src[3]][dest[3]]; + dest[4] = table[src[4]][dest[4]]; + } + } + } +} + +static int doit(struct filter *f, int flags, int time1) +{ + int val, n; + int time = time1; + struct blurdata *s = (struct blurdata *) f->data; + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + s->counter += time; + if (val & CHANGED) + s->counter = 0; + n = (int) ((1 - pow(1.0 - AMOUNT, (time + s->bckuptime) / DIV)) * 256); + if (s->counter >= 2 * MAXFRAMES) { + return val; + } + if (n < 10) { + s->bckuptime += time; + return val | ANIMATION; + } + s->bckuptime = 0; + if (s->counter >= MAXFRAMES) + n = 256, s->counter = 2 * MAXFRAMES; + if (s->n != n) { + s->n = n; + switch (f->image->bytesperpixel) { + case 1: + if (s->table == NULL) + s->table = (unsigned char (*)[256]) malloc(256 * 256); + blur8(f); + break; + case 3: + case 4: + if (s->table == NULL) + s->table = (unsigned char (*)[256]) malloc(256 * 256); + blurtruecolor(f); + break; + default: + if (s->table != NULL) + free(s->table), s->table = NULL; + } + } + switch (f->image->palette->type) { + case C256: + case GRAYSCALE: + xth_function(blur82, f, f->image->height); + break; +#ifdef SUPPORT16 + case TRUECOLOR16: + xth_function(blur16, f, f->image->height); + break; +#endif + case TRUECOLOR: + xth_function(blur32, f, f->image->height); + break; +#ifdef STRUECOLOR24 + case TRUECOLOR24: + xth_function(blur24, f, f->image->height); + break; +#endif + } + xth_sync(); + if (s->counter == 2 * MAXFRAMES) { + return val | CHANGED; + } + return val | CHANGED | ANIMATION; +} + +static void myremovefilter(struct filter *f) +{ + struct blurdata *s = (struct blurdata *) f->data; + if (s->savedpalette != NULL) { + restorepalette(f->image->palette, s->savedpalette); + destroypalette(s->savedpalette); + s->savedpalette = NULL; + } +} + +CONST struct filteraction blur_filter = { + "Motionblur", + "blur", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertupgeneric, + convertdowngeneric, + myremovefilter +}; diff --git a/src/engine/btrace.c b/src/engine/btrace.c new file mode 100644 index 0000000..3c02570 --- /dev/null +++ b/src/engine/btrace.c @@ -0,0 +1,596 @@ +#include +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include +#endif +#include +#include +#include +#include +#else +#include +#include +#include +#endif +#define SLARGEITER +#include +#include +#include +/* + * This is an implementation of famous boundary trace algorithm. + * See fractint documentation if you don't know what this means :) + * + * Here is two different implentation of this algorithm - one is faster + * and second is threadable. + * + * An faster one is quite usual implementation - get first uncalculated pixel, + * trace algorithm using labirinth "right hand rule" way (well, I currently + * use left hand rule) then trace same boundary again and fill. It is + * implemented in tracerectangle/tracecolor + * + * An threaded one follows description I sent to sci.fractals: + Hi + few weeks ago I asked for multithreaded algorithm for boundary trace + I received following reply by Paul Derbyshire + > One method is this. One b-trace algorithm pushes pixels onto a stack. + > Initially the screen border pixels are all pushed. Then a loop starts. A + > pixel is popped and calculated or recalled, with 4 orthogonal neighbors + > calculated or recalled if already calculated; if the central pixel is at a + > color boundary the neighbors are pushed. The image is done when the stack + > hits empty, then empty areas of image are floodfilled by their boundary + > color. (Fractint does it differently, not sure how). By this method, the + > stack will usually have at least 4 pixels, and so four substacks can be + > assigned to each of 4 processors, and each processor has a "processor to + > its left" designated as if they were in a "logical" ring. Each processor + > pushes new pixels on the processor to its left's substack, and pops from + > its own. This way, busy parts of the image wind up spread among all + > processors. By adding substacks, this can be expanded to accomodate more + > processors. Some amount is optimal, after which a point of diminishing + > returns is reached when most processors only do a few pixels and spend + > most of their time waiting for new stuff from the processor to its right. + > You'll need to figure out this optimum somehow; I can't guess what it + > would be. Probably around 64 processors. (More than that, you would do + > well just to assign separate processors small rectangular subsets of the + > image anyways.) Also, the end is only reached when NO processors have + > anything in their stacks. + This method looks very interesting but has few serious problems. + Most significant probably is that it always caluclates pixels up + to distance 3 from boundary. Simple modification should lower it + to distance 2. But "right hand rule" based algorithm should actualy + calculate points just to distance 1. So I want to implement such alrogithm, + since number of caluclated points is still significant. + + So I think I have to extend stack for two informations: + 1) direction + 2) color of boundary I am tracking(not color I am at) + and main algorithm should look like: + 1) detect color of current point + 2) look right. Is there same color? + yes:add point at the right to stack and exit + is there boundary color? + no:we are meeting boundary with different color - so we need + to track this boundary too. add point at right to stack with oposite + direction and boundary color set to current color + 3) look forward: similiar scheme as to look right + 4) look left: again similiar + 5) exit + + This hould trace boundaries to distance 1 (I hope) and do not miss anything. + Problem is that this algorithm never ends, since boundaries will be rescaned + again and again. So I need to add an caluclated array wich should looks like: + for every point has mask for all directions that were scaned+calculated mask + (set to 1 if pixel is already calculated)+inprocess mask(set to 1 if some + other processor is currently calculating it) + + Scan masks should be set in thime when pixel is added to stack and pixel + should not be added in case that mask is already set. I don't this that locks + to this array is required since time spent by setting masks should be quite + small and possible race conditions should not be drastical(except recalculating + some point) + + I was also thinking about perCPU queues. I think that one queue is OK, + it is simplier and should not take much more time(except it will be locked + more often but time spend in locked queue in comparsion to time spent + in rest should be so small so this should not be drastical for less than 10 + procesors) + + At the other hand - perCPU queues should have one advantage - each + cpu should own part of image and points from its part will be added to + this cpu. This should avoid procesor cache conflict and speed up process. + At the other hand, when cpu's queue is empty, cpu will have to browse + others queues too and steal some points from other CPU, wich should introduce + some slowdown and I am not sure if this way will bring any improvement. + + Other think that should vote for perCPU queue is fact, that in one CPU + queue should be more often situations when queue is empty since one procesor + is caluclating points and other has wait, since it had tendency to trace + just one boundary at the time. At the other hand, most of boundaries should + cross broders, so they should be added to queue at the initialization, so + this should be OK. + + I am beginer to threds, SMP etc. So I looking for ideas, and suggestions + to improve this alg. (or design different one). + Also someone with SMP box, who should test me code is welcomed. + BTW whats is the average/maximal number of CPU in todays SMP boxes? + + Please reply directly to my email:hubicka@paru.cas.cz + + Thanks + Honza + * This way is implemented in tracerectangle2/tracepoint. It is enabled + * just when threads are compiled in. Also when nthreads=1, old faster + * algorithm is used. + * + * Implementation notes: + * 1) I decided to use one queue instead of stack, since I expect, it will + * have tendency to trace all boundaries at the time, not just one. + * This will make queue bigger and reduce probability of situation, where + * queue is empty and other processors has to wait for one, that is + * calculating and should add something there (maybe :) + * 2) Stack (queue :) is used just when neccesary - in situations where queue + * is quite full (there is more items than 10) procesor just continues in + * tracing path it started. This reduces number of slow stack operations, + * locks/unlocks, cache conflicts and other bad thinks. + * 3) Just each fourth pixel should be added into queue + * 4) Foodfill algorithm should be avoided since colors at the boundaries + * are always correct, we should simply go trought each scanline and when + * pixel is uncalcualted, copy value from its left neighbor + * + * Current implementation has about 6% lower results than "fast" algorithm + * using one thread. When two threads enabled (at my one processor linux + * box) lock/unlock overhead eats next 8%, three threads eats next 1% :) + */ +#ifdef HAVE_ALLOCA_H +#include +#endif +#include + +#include +#include +#include +#include "calculate.h" + +#define UP 0 +#define RIGHT 1 +#define DOWN 2 +#define LEFT 3 +#define turnleft(d) (((d)+3)&3) +#define turnright(d) (((d)+1)&3) +#define turnoposite(d) (((d)+2)&3) +#define callwait() if(cfilter.wait_function!=NULL) cfilter.wait_function(&cfilter); + + +#ifndef nthreads +static int size; +static unsigned int inset; +static int nwaiting; +static int exitnow; +#define PAGESHIFT 14 +#define PAGESIZE (1<=maxsize) if(nstack>=nthreads-1) nstack=0; else nstack++; \ + page=sizes[nstack]>>PAGESHIFT; \ + if(page==npages[nstack]) starts[nstack][npages[nstack]]=(struct stack *)malloc(sizeof(struct stack)*PAGESIZE),npages[nstack]++;\ + ptr=starts[nstack][page]+(sizes[nstack]&(PAGESIZE-1)); \ + ptr->x=sx; \ + ptr->y=sy; \ + if(periodicity) \ + ptr->direction=d|8; else \ + ptr->direction=d; \ + ptr->color=c; \ + size++; \ + sizes[nstack]++; \ + if(nwaiting) xth_wakefirst(0); \ + } \ + xth_unlock(0); \ +} +/*Non locking one used by init code */ +#define addstack1(sx,sy,d,c) { \ + int page; \ + struct stack *ptr; \ + int nstack=(((sy)-y1)*nthreads)/(y2-y1+1); \ + calculated[sx+sy*CALCWIDTH]|=1<=maxsize) if(nstack==nthreads-1) nstack=0; else nstack++; \ + page=sizes[nstack]>>PAGESHIFT; \ + if(page==npages[nstack]) starts[nstack][npages[nstack]]=(struct stack *)malloc(sizeof(struct stack)*PAGESIZE),npages[nstack]++; \ + ptr=starts[nstack][page]+(sizes[nstack]&(PAGESIZE-1)); \ + ptr->x=sx; \ + ptr->y=sy; \ + ptr->direction=d|8; \ + ptr->color=c; \ + size++; \ + sizes[nstack]++; \ + } \ +} +static int xstart, ystart, xend, yend; +#endif + +static unsigned char *calculated; +#define CALCULATED 16 +#define CALCULATING 32 +#define CALCWIDTH cimage.width + +static number_t *xcoord, *ycoord; +#ifndef inline +REGISTERS(3) +CONSTF static pixel32_t calculatepixel(int x, int y, int peri) +{ + return (calculate(xcoord[x], ycoord[y], peri)); +} +#else +#define calculatepixel(x,y,peri) (calculate(xcoord[x],ycoord[y],peri)) +#endif +#define putpixel(x,y,c) p_setp((cpixel_t *)cimage.currlines[y],x,c) +#define getpixel(x,y) p_getp((cpixel_t *)cimage.currlines[y],x) +#include +#define tracecolor tracecolor8 +#define tracepoint tracepoint8 +#define dosymetries dosymetries8 +#define queue queue8 +#define bfill bfill8 +#include "btraced.c" +#include +#define tracecolor tracecolor16 +#define tracepoint tracepoint16 +#define dosymetries dosymetries16 +#define queue queue16 +#define bfill bfill16 +#include "btraced.c" +#include +#define tracecolor tracecolor24 +#define tracepoint tracepoint24 +#define dosymetries dosymetries24 +#define queue queue24 +#define bfill bfill24 +#include "btraced.c" +#include +#define tracecolor tracecolor32 +#define tracepoint tracepoint32 +#define dosymetries dosymetries32 +#define queue queue32 +#define bfill bfill32 +#include "btraced.c" + +#ifdef HAVE_GETTEXT +#include +#else +#define gettext(STRING) STRING +#endif + +#ifndef SLOWCACHESYNC +#ifndef nthreads +static int tracerectangle2(int x1, int y1, int x2, int y2) +{ + int x, y; + cfilter.max = y2 - y1; + cfilter.pass = gettext("Boundary trace"); + cfilter.pos = 0; + maxsize = MAXPAGES / nthreads; + for (y = 0; y < nthreads; y++) { + npages[y] = 0; /*stack is empty */ + sizes[y] = 0; + starts[y] = pages + y * maxsize; + } + maxsize *= PAGESIZE; + maxsize2 = maxsize * nthreads; + size = 0; + nwaiting = 0; + exitnow = 0; + inset = cpalette.pixels[0]; + for (y = y1; y <= y2; y++) { + memset_long(calculated + x1 + y * CALCWIDTH, 0, x2 - x1 + 1); + } + for (x = x1; x <= x2; x += 4) { + addstack1(x, y1, LEFT, INT_MAX); + addstack1(x, y2, RIGHT, INT_MAX); + } + for (y = y1; y <= y2; y += 4) { + addstack1(x1, y, DOWN, INT_MAX); + addstack1(x2, y, UP, INT_MAX); + } + xstart = x1; + ystart = y1; + xend = x2; + yend = y2; + switch (cimage.bytesperpixel) { + case 1: + xth_function(queue8, NULL, 1); + xth_sync(); + xth_function(bfill8, NULL, yend - ystart - 1); + break; +#ifdef SUPPORT16 + case 2: + xth_function(queue16, NULL, 1); + xth_sync(); + xth_function(bfill16, NULL, yend - ystart - 1); + break; +#endif +#ifdef STRUECOLOR24 + case 3: + xth_function(queue24, NULL, 1); + xth_sync(); + xth_function(bfill24, NULL, yend - ystart - 1); + break; +#endif + case 4: + xth_function(queue32, NULL, 1); + xth_sync(); + xth_function(bfill32, NULL, yend - ystart - 1); + break; + } + xth_sync(); + for (y = 0; y < nthreads; y++) + for (x = 0; x < npages[y]; x++) + free(starts[y][x]); /*free memory allocated for stack */ + return 1; +} +#endif +#endif +static void skip(int x1, int y1, int x2, int y2) +{ + int src = y1; + int xstart = x1 * cimage.bytesperpixel; + int xsize = (x2 - x1 + 1) * cimage.bytesperpixel; + y1++; + for (; y1 <= y2; y1++) { + memcpy(cimage.currlines[y1] + xstart, + cimage.currlines[src] + xstart, xsize); + ycoord[y1] = ycoord[src]; + } +} + +static int tracerectangle(int x1, int y1, int x2, int y2) +{ + int x, y; + unsigned char *calc; + cfilter.max = y2 - y1; + cfilter.pass = gettext("Boundary trace"); + cfilter.pos = 0; + for (y = y1; y <= y2; y++) { + memset_long(calculated + x1 + y * CALCWIDTH, 0, + (size_t) (x2 - x1 + 1)); + } + switch (cimage.bytesperpixel) { + case 1: + for (y = y1; y <= y2; y++) { + calc = calculated + y * CALCWIDTH; + for (x = x1; x <= x2; x++) + if (!calc[x]) { + tracecolor8(x1, y1, x2, y2, x, y); + } + cfilter.pos = y - y1; + callwait(); + if (cfilter.interrupt) { + skip(x1, y, x2, y2); + return 0; + } + } + break; +#ifdef SUPPORT16 + case 2: + for (y = y1; y <= y2; y++) { + calc = calculated + y * CALCWIDTH; + for (x = x1; x <= x2; x++) + if (!calc[x]) { + tracecolor16(x1, y1, x2, y2, x, y); + } + cfilter.pos = y - y1; + callwait(); + if (cfilter.interrupt) { + skip(x1, y, x2, y2); + return 0; + } + } + break; +#endif +#ifdef STRUECOLOR24 + case 3: + for (y = y1; y <= y2; y++) { + calc = calculated + y * CALCWIDTH; + for (x = x1; x <= x2; x++) + if (!calc[x]) { + tracecolor24(x1, y1, x2, y2, x, y); + } + cfilter.pos = y - y1; + callwait(); + if (cfilter.interrupt) { + skip(x1, y, x2, y2); + return 0; + } + } +#endif + case 4: + for (y = y1; y <= y2; y++) { + calc = calculated + y * CALCWIDTH; + for (x = x1; x <= x2; x++) + if (!calc[x]) { + tracecolor32(x1, y1, x2, y2, x, y); + } + cfilter.pos = y - y1; + callwait(); + if (cfilter.interrupt) { + skip(x1, y, x2, y2); + return 0; + } + } + break; + } + return 1; +} + +int +boundarytrace(int x1, int y1, int x2, int y2, number_t * xpos, + number_t * ypos) +{ + int i; + int i1; + int xsym, ysym; + int cy1, cy2; + int cx1, cx2; + int ydiv; +#ifdef HAVE_ALLOCA + calculated = (unsigned char *) alloca(cimage.width * (y2 + 1)); +#else + calculated = (unsigned char *) malloc(cimage.width * (y2 + 1)); +#endif + if (calculated == NULL) { + return 0; + } + xcoord = xpos; + ycoord = ypos; + + + if (cursymetry.xsym < cfractalc.rs.nc + || cursymetry.xsym > cfractalc.rs.mc) + xsym = -10; + else + xsym = + (int) (0.5 + + ((cursymetry.xsym - + cfractalc.rs.nc) * cimage.width / (cfractalc.rs.mc - + cfractalc.rs.nc))); + if (cursymetry.ysym < cfractalc.rs.ni + || cursymetry.ysym > cfractalc.rs.mi) + ysym = -10; + else + ysym = + (int) (0.5 + + ((cursymetry.ysym - + cfractalc.rs.ni) * cimage.height / (cfractalc.rs.mi - + cfractalc.rs. + ni))); + ydiv = + (int) (0.5 + + ((-cfractalc.rs.ni) * cimage.height / + (cfractalc.rs.mi - cfractalc.rs.ni))); + if (xsym > x1 && xsym < x2) { + if (xsym - x1 > x2 - xsym) + cx1 = x1, cx2 = xsym; + else + /*xsym--, */ cx1 = xsym, cx2 = x2; + } else + xsym = -1, cx1 = x1, cx2 = x2; + if (ysym > y1 && ysym < y2) { + if (ysym - y1 > y2 - ysym) + cy1 = y1, cy2 = ysym; + else + cy1 = ysym, cy2 = y2; + } else + ysym = -1, cy1 = y1, cy2 = y2; + for (i = cx1; i <= cx2; i++) { + xcoord[i] = + cfractalc.rs.nc + i * (cfractalc.rs.mc - + cfractalc.rs.nc) / cimage.width; + } + for (i = cy1; i <= cy2; i++) { + ycoord[i] = + cfractalc.rs.ni + i * (cfractalc.rs.mi - + cfractalc.rs.ni) / cimage.height; + } + i = 1; +#ifndef SLOWCACHESYNC +#ifndef nthreads + if (nthreads != 1) { + if (ydiv > cy1 && ydiv < cy2) { + i |= tracerectangle2(cx1, cy1, cx2, ydiv), + i |= tracerectangle2(cx1, ydiv, cx2, cy2); + } else + i |= tracerectangle2(cx1, cy1, cx2, cy2); + } else +#endif +#endif + { + if (ydiv > cy1 && ydiv < cy2) { + i |= tracerectangle(cx1, cy1, cx2, ydiv), + i |= tracerectangle(cx1, ydiv, cx2, cy2); + } else + i |= tracerectangle(cx1, cy1, cx2, cy2); + } + if (!i) { +#ifndef HAVE_ALLOCA + free(calculated); +#endif + return 0; + } +#ifndef HAVE_ALLOCA + free(calculated); +#endif + drivercall(cimage, + dosymetries8(x1, x2, y1, y2, xsym, cx1, cx2), + dosymetries16(x1, x2, y1, y2, xsym, cx1, cx2), + dosymetries24(x1, x2, y1, y2, xsym, cx1, cx2), + dosymetries32(x1, x2, y1, y2, xsym, cx1, cx2)); + for (i = cx1; i <= cx2; i++) { + if (xsym != -1) { + i1 = 2 * xsym - i; + if (i1 >= x1 && i1 <= x2 && i != i1) + xcoord[i1] = 2 * cursymetry.xsym - xcoord[i]; + } + } + for (i = cy1; i <= cy2; i++) { + if (ysym != -1) { + i1 = 2 * ysym - i; + if (i1 >= y1 && i1 <= y2 && i != i1) + ycoord[i1] = 2 * cursymetry.ysym - ycoord[i]; + } + } + if (cy1 != y1) { + register int yy1, yy2; + int xstart = x1 * cimage.bytesperpixel; + int xsize = (x2 - x1 + 1) * cimage.bytesperpixel; + yy1 = y1; + yy2 = 2 * ysym - y1; + while (yy1 < yy2) { + memcpy(cimage.currlines[yy1] + xstart, + cimage.currlines[yy2] + xstart, (size_t) xsize); + yy1++; + yy2--; + } + } + if (cy2 != y2) { + register int yy1, yy2; + int xstart = x1 * cimage.bytesperpixel; + int xsize = (x2 - x1 + 1) * cimage.bytesperpixel; + yy1 = y2; + yy2 = 2 * ysym - y2; + while (yy1 > yy2) { + memcpy(cimage.currlines[yy1] + xstart, + cimage.currlines[yy2] + xstart, (size_t) xsize); + yy1--; + yy2++; + } + } + return 1; +} + +int boundarytraceall(number_t * xpos, number_t * ypos) +{ + return (boundarytrace + (0, 0, cimage.width - 1, cimage.height - 1, xpos, ypos)); +} diff --git a/src/engine/btraced.c b/src/engine/btraced.c new file mode 100644 index 0000000..e0073c0 --- /dev/null +++ b/src/engine/btraced.c @@ -0,0 +1,466 @@ +#ifndef UNSUPPORTED +REGISTERS(3) +static void +tracecolor(int xstart, int ystart, int xend, int yend, register int + x, register int y) +{ + int dir = RIGHT, fill = 0; + register unsigned char *calc; + int peri = 0; + cpixeldata_t c = (cpixeldata_t) calculatepixel(x, y, 0); + cpixeldata_t w = (cpixeldata_t) 0; + cpixeldata_t inset = (cpixeldata_t) cpalette.pixels[0]; + putpixel(x, y, c); + calc = calculated + x + y * CALCWIDTH; + *calc = (unsigned char) 1; + while (x > xstart && getpixel(x - 1, y) == c) + x--, calc--; + *calc = (unsigned char) 2; + if (c == inset) + peri = 1; + do { + if (!fill && !*calc) { + *calc = (unsigned char) 1; + putpixel(x, y, c); + } + switch (dir) { + case RIGHT: + if (y > ystart) { + if (!*(calc - CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y - 1, peri); + putpixel(x, y - 1, w); + *(calc - CALCWIDTH) = (unsigned char) 1; + } else + w = getpixel(x, y - 1); + if (w == c) { + dir = UP; + calc -= CALCWIDTH; + y--; + break; + } + } + + if (x < xend) { + if (!*(calc + 1)) { + w = (cpixeldata_t) calculatepixel(x + 1, y, peri); + putpixel(x + 1, y, w); + *(calc + 1) = (unsigned char) 1; + } else + w = getpixel(x + 1, y); + if (w == c) { + calc++; + x++; + break; + } + } + + if (y < yend) { + if (!*(calc + CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y + 1, peri); + putpixel(x, y + 1, w); + *(calc + CALCWIDTH) = (unsigned char) 1; + } else + w = getpixel(x, y + 1); + if (w == c) { + dir = DOWN; + calc += CALCWIDTH; + y++; + break; + } + } + + if (*calc == (unsigned char) 2) { + *calc = (unsigned char) 1; + return; + } + + dir = LEFT; + x--; + calc--; + break; + + case LEFT: + if (y < yend) { + if (!*(calc + CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y + 1, peri); + putpixel(x, y + 1, w); + *(calc + CALCWIDTH) = (unsigned char) 1; + } else + w = getpixel(x, y + 1); + if (w == c) { + dir = DOWN; + calc += CALCWIDTH; + y++; + break; + } + } + + if (x > xstart) { + if (!*(calc - 1)) { + w = (cpixeldata_t) calculatepixel(x - 1, y, peri); + putpixel(x - 1, y, w); + *(calc - 1) = (unsigned char) 1; + } else + w = getpixel(x - 1, y); + if (w == c) { + calc--; + x--; + break; + } + } + + if (y > ystart) { + if (!*(calc - CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y - 1, peri); + putpixel(x, y - 1, w); + *(calc - CALCWIDTH) = (unsigned char) 1; + } else + w = getpixel(x, y - 1); + if (w == c) { + dir = UP; + calc -= CALCWIDTH; + y--; + break; + } + } + + + dir = RIGHT; + x++; + calc++; + break; + + case UP: + if (fill) { + unsigned char *calc1; + cpixel_t *pixel1; + calc1 = calc + 1; + pixel1 = p_add((cpixel_t *) cimage.currlines[y], x + 1); + while (pixel1 <= + p_add((cpixel_t *) cimage.currlines[y], xend)) { + if (!*calc1) + *calc1 = (unsigned char) 1, p_set(pixel1, c); + else if (p_get(pixel1) != c) + break; + p_inc(pixel1, 1); + calc1++; + } + } + if (x > xstart) { + if (!*(calc - 1)) { + w = (cpixeldata_t) calculatepixel(x - 1, y, peri); + putpixel(x - 1, y, w); + *(calc - 1) = (unsigned char) 1; + } + w = getpixel(x - 1, y); + if (w == c) { + dir = LEFT; + calc--; + x--; + break; + } + } + + if (y > ystart) { + if (!*(calc - CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y - 1, peri); + putpixel(x, y - 1, w); + *(calc - CALCWIDTH) = (unsigned char) 1; + } + w = getpixel(x, y - 1); + if (w == c) { + calc -= CALCWIDTH; + y--; + break; + } + } + + if (x < xend) { + if (!*(calc + 1)) { + w = (cpixeldata_t) calculatepixel(x + 1, y, peri); + putpixel(x + 1, y, w); + *(calc + 1) = (unsigned char) 1; + } else + w = getpixel(x + 1, y); + if (w == c) { + dir = RIGHT; + calc++; + x++; + break; + } + } + + dir = DOWN; + y++; + calc += CALCWIDTH; + break; + case DOWN: + if (x < xend) { + if (!*(calc + 1)) { + w = (cpixeldata_t) calculatepixel(x + 1, y, peri); + putpixel(x + 1, y, w); + *(calc + 1) = (unsigned char) 1; + } else + w = getpixel(x + 1, y); + if (w == c) { + dir = RIGHT; + calc++; + x++; + break; + } + } + + if (y < yend) { + if (!*(calc + CALCWIDTH)) { + w = (cpixeldata_t) calculatepixel(x, y + 1, peri); + putpixel(x, y + 1, w); + *(calc + CALCWIDTH) = (unsigned char) 1; + } else + w = getpixel(x, y + 1); + if (w == c) { + dir = DOWN; + calc += CALCWIDTH; + y++; + break; + } + } + + if (x > xstart) { + if (!*(calc - 1)) { + w = (cpixeldata_t) calculatepixel(x - 1, y, peri); + putpixel(x - 1, y, w); + *(calc - 1) = (unsigned char) 1; + } else + w = getpixel(x - 1, y); + if (w == c) { + dir = LEFT; + calc--; + x--; + break; + } + } + + dir = UP; + calc -= CALCWIDTH; + y--; + break; + + } + if (*calc == (unsigned char) 2) { + if (fill) { + *calc = (unsigned char) 1; + return; + } + fill = 1; + dir = RIGHT; + } + } + while (1); +} + +#ifndef SLOWCACHESYNC +#ifndef nthreads +#define ethreads 1 +REGISTERS(3) +static INLINE void +tracepoint(int xp, int yp, int dir, unsigned int color, int xstart, + int xend, int ystart, int yend) +{ + unsigned char *calc; + cpixeldata_t mycolor; + int i, lookdir; + unsigned int c; + int x, y; + int periodicity = (dir & 8) != 0; + dir &= ~8; + calc = calculated + xp + yp * CALCWIDTH; + + if (!(*calc & (CALCULATED | CALCULATING))) { + *calc |= CALCULATING; + mycolor = (cpixeldata_t) calculatepixel(xp, yp, periodicity); + putpixel(xp, yp, mycolor); + *calc |= CALCULATED; + *calc &= ~CALCULATING; + } else { + if (*calc & CALCULATING) { + /*Bad luck..some other procesor is working with out pixel :) try + *later.*/ + addstack(xp, yp, dir, color, periodicity); + return; + } + mycolor = getpixel(xp, yp); + } + + while (1) { + periodicity = (mycolor == inset || color == inset); + lookdir = turnright(dir); + for (i = 0; i < 3; i++) { + x = xp + dirrections[lookdir][0]; + y = yp + dirrections[lookdir][1]; + if (x >= xstart && x <= xend && y >= ystart && y <= yend) { + calc = calculated + x + y * CALCWIDTH; + if (!(*calc & (CALCULATED | CALCULATING))) { + *calc |= CALCULATING; + c = calculatepixel(x, y, periodicity); + putpixel(x, y, c); + *calc |= CALCULATED; + *calc &= ~CALCULATING; + } else { + if (*calc & CALCULATING) { + /*Bad luck..some other procesor is working with out pixel :) try + *later.*/ + addstack(xp, yp, dir, color, periodicity); + return; + } + c = getpixel(x, y); + } + if (c == mycolor) + break; + if (c != color) { + int dir2 = turnright(lookdir); + int mask = (1 << dir2) + (1 << turnright(dir2)); + if (!(*calc & mask)) { + addstack(x, y, dir2, mycolor, periodicity); + } + color = c; + } + } + lookdir = turnleft(lookdir); + } + x = xp + dirrections[lookdir][0]; + y = yp + dirrections[lookdir][1]; + if (x >= xstart && x <= xend && y >= ystart && y <= yend) { + calc = calculated + x + y * CALCWIDTH; + if (!(*calc & (1 << lookdir))) { + *calc |= (1 << lookdir); + if (size < 10) { + addstack(x, y, lookdir, color, periodicity); + return; + } else { + xp = x; + yp = y; + dir = lookdir; + calc = calculated + xp + yp * CALCWIDTH; + } + } else + return; + } else + return; + } +} + +static void queue(void *data, struct taskinfo *task, int r1, int r2) +{ + int x, y, d, c; + int pos = 0; + + while (1) { + int nstack; + xth_lock(0); + while (!size) { /*Well stack is empty. */ + if (exitnow) { /*Possibly everything is done now.. */ + xth_unlock(0); + return; + } + if (nwaiting == nthreads - 1) { /*We are last working CPU */ + exitnow = 1; /*So we should exit now */ + xth_wakeup(0); /*Wake up all waiting tasks */ + xth_unlock(0); + return; /*and exit :) */ + } + nwaiting++; /*We are not latest task. */ + xth_sleep(0, 0); /*Wait until other task will push some data */ + nwaiting--; + if (exitnow) { /*Evrything is done now? */ + xth_unlock(0); + return; + } + } + nstack = xth_nthread(task); + while (!sizes[nstack]) + if (nstack != nthreads - 1) + nstack++; + else + nstack = 0; + sizes[nstack]--; + size--; + pos++; + if (pos >= sizes[nstack]) + pos = 0; + x = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].x; + y = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].y; + d = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)]. + direction; + c = starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)].color; + /* Well stack currently is queue. Should have better results at + * SMP, since has tendency trace all ways at time, so (I believe) + * should avoid some cache conflict and situation where queue is + * empty. At the other hand, makes queue bigger and needs following + * copy: + */ + starts[nstack][pos >> PAGESHIFT][pos & (PAGESIZE - 1)] = + starts[nstack][sizes[nstack] >> PAGESHIFT][sizes[nstack] & + (PAGESIZE - 1)]; + xth_unlock(0); + tracepoint(x, y, d, c, xstart, xend, ystart, yend); + } +} + +static void bfill(void *dat, struct taskinfo *task, int r1, int r2) +{ + int y; + cpixel_t *pos, *end; + unsigned char *data; + r1 += ystart + 1; + r2 += ystart + 1; + for (y = r1; y < r2; y++) { + pos = p_add((cpixel_t *) cimage.currlines[y], xstart + 1); + end = p_add((cpixel_t *) cimage.currlines[y], xend); + data = calculated + xstart + y * CALCWIDTH + 1; + for (; pos < end; p_inc(pos, 1), data++) { + if (!*data) + p_copy(pos, 0, pos, -1); + } + } +} + +#undef ethreads +#endif +#endif +static void +dosymetries(int x1, int x2, int y1, int y2, int xsym, int cx1, int cx2) +{ + if (cx1 != x1) { + register int y; + register cpixel_t *xx1, *xx2; + for (y = y1; y <= y2; y++) { + xx1 = p_add((cpixel_t *) cimage.currlines[y], x1); + xx2 = p_add((cpixel_t *) cimage.currlines[y], 2 * xsym - x1); + while (xx1 < xx2) { + p_copy(xx1, 0, xx2, 0); + p_inc(xx1, 1); + p_inc(xx2, -1); + } + } + } + if (cx2 != x2) { + register int y; + register cpixel_t *xx1, *xx2; + for (y = y1; y <= y2; y++) { + xx1 = p_add((cpixel_t *) cimage.currlines[y], x2); + xx2 = p_add((cpixel_t *) cimage.currlines[y], 2 * xsym - x2); + while (xx1 > xx2) { + p_copy(xx1, 0, xx2, 0); + p_inc(xx1, -1); + p_inc(xx2, 1); + } + } + } +} +#endif + +#undef dosymetries +#undef tracepoint +#undef tracecolor +#undef queue +#undef bfill diff --git a/src/engine/calculate.h b/src/engine/calculate.h new file mode 100644 index 0000000..ab6ca40 --- /dev/null +++ b/src/engine/calculate.h @@ -0,0 +1,37 @@ + +static pixel32_t INLINE +calculate(number_t x, number_t y, int periodicity) CONSTF; +static pixel32_t INLINE calculate(number_t x, number_t y, int periodicity) +{ + pixel32_t i; + + rotateback(cfractalc, x, y); + if (cfractalc.plane) { + recalculate(cfractalc.plane, &x, &y); + } + STAT(ncalculated2++); +#ifndef SLOWFUNCPTR + if (cfractalc.mandelbrot) { + if (cformula.flags & STARTZERO) + i = cfractalc.calculate[periodicity] (cfractalc.bre, + cfractalc.bim, x, y); + else + i = cfractalc.calculate[periodicity] (x + cfractalc.bre, + y + cfractalc.bim, x, y); + } else + i = cfractalc.calculate[periodicity] (x, y, cfractalc.pre, + cfractalc.pim); +#else + if (cfractalc.mandelbrot) { + if (cformula.flags & STARTZERO) + i = calculateswitch(cfractalc.bre, cfractalc.bim, x, y, + periodicity); + else + i = calculateswitch(x + cfractalc.bre, y + cfractalc.bim, x, y, + periodicity); + } else + i = calculateswitch(x, y, cfractalc.pre, cfractalc.pim, + periodicity); +#endif + return (i); +} diff --git a/src/engine/dither.c b/src/engine/dither.c new file mode 100644 index 0000000..f46de36 --- /dev/null +++ b/src/engine/dither.c @@ -0,0 +1,1200 @@ +/* + * This file contains code of three conversion filters based at dithering: + * truecolor conversion filter - it should convert 8bpp, fixedcolor and + * bitmaps to truecolor + * fixedcolor conversion - emulates user palette at 8bpp displays with static + * palette + * bitmap conversion - emulates 8bpp at 1bpp displays. + * + * Since this filters share quite a lot code, they are implemented in one + * file. Internal loops are quire messy, since they are optimized for speed. + * Let me know about all ideas to make it faster. + * + * Note that quite interesting alg. is for preparing dithering table at + * fixedcolor displays. + */ +#include +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include +#endif +#include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif +#include +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#define MSIZE 8 +static CONST unsigned char matrix[MSIZE][MSIZE] = { + {0, 192, 48, 240, 12, 204, 60, 252,}, + {128, 64, 176, 112, 140, 76, 188, 124,}, + {32, 224, 16, 208, 44, 236, 28, 220,}, + {160, 96, 144, 80, 172, 108, 156, 92,}, + {8, 200, 56, 248, 4, 196, 52, 244,}, + {136, 72, 184, 120, 132, 68, 180, 116,}, + {40, 232, 24, 216, 36, 228, 20, 212,}, + {168, 104, 152, 88, 164, 100, 148, 84}, +}; + +struct ditherdata { + unsigned char table[32][32][32]; + int rmat[MSIZE][MSIZE]; + int gmat[MSIZE][MSIZE]; + int bmat[MSIZE][MSIZE]; + struct palette *palette; + int active; +}; +struct fixeddata { + /*6kKb of table */ + unsigned char ctable[8][8][256]; + /*and 32kB */ + unsigned char table[32][32][32]; + /*and 768 bytes... */ + int rmat[MSIZE][MSIZE]; + int gmat[MSIZE][MSIZE]; + int bmat[MSIZE][MSIZE]; + struct palette *palette; + int forversion; + int active; + int fixcolor; +}; +struct bitmapdata { + struct palette *palette; + int intensity[256]; + int forversion; + int active; + int fixcolor; +}; +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags &= ~IMAGEDATA; + r->supportedmask = + FIXEDCOLOR | MASK1BPP | MASK3BPP | MASK2BPP | MASK4BPP | BITMAPS; + return (f->next->action->requirement(f->next, r)); +} + +#ifdef SFIXEDCOLOR +/* create_rgb_table: + * Fills an lookup table with conversion data for the specified + * palette. + * + * Uses alg. similiar to foodfill - it adds one seed per every color in + * palette to its best possition. Then areas around seed are filled by + * same color because it is best aproximation for them, and then areas + * about them etc... + * + * It does just about 80000 tests for distances and this is about 100 + * times better than normal 256*32000 tests so the caluclation time + * is now less than one second at all computers I tested. + */ +#define UNUSED 65535 +#define LAST 65532 + +/* macro add adds to single linked list */ +#define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \ + (first != LAST ? (next[last] = (i)) : (first = (i))), \ + (last = (i))) : 0) + + /* same but w/o checking for first element */ +#define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \ + next[last] = (i), \ + (last = (i))) : 0) + + /* calculates distance between two colors */ +#define dist(a1, a2, a3, b1, b2, b3) \ + (col_diff[0][((a2) - (b2)) & 0x1FF] + \ + col_diff[1][((a1) - (b1)) & 0x1FF] + \ + col_diff[2][((a3) - (b3)) & 0x1FF]) + + /* converts r,g,b to position in array and back */ +#define pos(r, g, b) \ +((((int)(r)) / 8) * 32 * 32 + (((int)(g)) / 8) * 32 + (((int)(b)) / 8)) + +#define depos(pal, r, g, b) \ + ((b) = ((unsigned int)(pal) & 31) * 8, \ + (g) = (((unsigned int)(pal) >> 5) & 31) * 8, \ + (r) = (((unsigned int)(pal) >> 10) & 31) * 8) + + /* is current color better than pal1? */ +#define better(r1, g1, b1, pal1) \ + (((int)dist((r1), (g1), (b1), \ + (int)(pal1)[0], (int)(pal1)[1], (int)(pal1)[2])) > (int)dist2) +#define better1(r1, g1, b1, pal1) \ + (((int)dist((r1), (g1), (b1), \ + (int)(pal1)[0], (int)(pal1)[1], (int)(pal1)[2]))) + + /* checking of possition */ +#define dopos(rp, gp, bp, ts) \ + if ((rp > -1 || r > 0) && (rp < 1 || r < 248) && \ + (gp > -1 || g > 0) && (gp < 1 || g < 248) && \ + (bp > -1 || b > 0) && (bp < 1 || b < 248)) { \ + i = first + rp * 32 * 32 + gp * 32 + bp; \ + if (ts ? data[i] != val : !data[i]) { \ + dist2 = (rp ? col_diff[1][(r+8*rp-(int)pal[val][0]) & 0x1FF] : r2) + \ + (gp ? col_diff[0][(g+8*gp-(int)pal[val][1]) & 0x1FF] : g2) + \ + (bp ? col_diff[2][(b+8*bp-(int)pal[val][2]) & 0x1FF] : b2); \ + if (better((r+8*rp), (g+8*gp), (b+8*bp), pal[data[i]])) { \ + data[i] = val; \ + add1 (i); \ + } \ + } \ + } + +static void +create_rgb_table(unsigned char table[32][32][32], struct palette *palette) +{ + int i, curr, r, g, b, val, r2, g2, b2, dist2; + rgb_t *pal = palette->rgb; + unsigned short *next; + unsigned char *data; + int first = LAST; + int last = LAST; + int count = 0; + + next = (unsigned short *) malloc(sizeof(short) * 32 * 32 * 32); + if (col_diff[0][1] == 0) + bestfit_init(); + + memset_long(next, 255, sizeof(short) * 32 * 32 * 32); + memset_long(table, palette->start, sizeof(char) * 32 * 32 * 32); + depos(32 * 32 * 32 - 1, r, g, b); + + data = (unsigned char *) table; + + /* add starting seeds for foodfill */ + for (i = palette->start + 1; i < palette->end; i++) { + curr = pos((int) pal[i][0], (int) pal[i][1], (int) pal[i][2]); + if (next[curr] == UNUSED) { + data[curr] = (unsigned int) i; + add(curr); + } + } + + /* main foodfill: two versions of loop for faster growing in blue axis */ + while (first != LAST) { + depos(first, r, g, b); + + /* calculate distance of current color */ + val = data[first]; + r2 = col_diff[1][(((int) pal[val][0]) - (r)) & 0x1FF]; + g2 = col_diff[0][(((int) pal[val][1]) - (g)) & 0x1FF]; + b2 = col_diff[2][(((int) pal[val][2]) - (b)) & 0x1FF]; + + /* try to grow to all directions */ + dopos(0, 0, 1, 1); + dopos(0, 0, -1, 1); + dopos(1, 0, 0, 1); + dopos(-1, 0, 0, 1); + dopos(0, 1, 0, 1); + dopos(0, -1, 0, 1); + + /* faster growing of blue direction */ + if ((b > 0) && (data[first - 1] == val)) { + b -= 8; + first--; + b2 = col_diff[2][(((int) pal[val][2]) - (b)) & 0x1ff]; + + dopos(-1, 0, 0, 0); + dopos(1, 0, 0, 0); + dopos(0, -1, 0, 0); + dopos(0, 1, 0, 0); + + first++; + } + + /* get next from list */ + i = first; + first = next[first]; + next[i] = UNUSED; + + /* second version of loop */ + if (first != LAST) { + depos(first, r, g, b); + + val = data[first]; + r2 = col_diff[1][(((int) pal[val][0]) - (r)) & 0x1ff]; + g2 = col_diff[0][(((int) pal[val][1]) - (g)) & 0x1ff]; + b2 = col_diff[2][(((int) pal[val][2]) - (b)) & 0x1ff]; + + dopos(0, 0, 1, 1); + dopos(0, 0, -1, 1); + dopos(1, 0, 0, 1); + dopos(-1, 0, 0, 1); + dopos(0, 1, 0, 1); + dopos(0, -1, 0, 1); + + if ((b < 248) && (data[first + 1] == val)) { + b += 8; + first++; + b2 = col_diff[2][(((int) pal[val][2]) - (b)) & 0x1ff]; + + dopos(-1, 0, 0, 0); + dopos(1, 0, 0, 0); + dopos(0, -1, 0, 0); + dopos(0, 1, 0, 0); + + first--; + } + + i = first; + first = next[first]; + next[i] = UNUSED; + } + + count++; + } + free(next); +} + +static void +checksizes(unsigned char table[32][32][32], int *RESTRICT red, + int *RESTRICT green, int *RESTRICT blue) +{ + int r, g, b; + int color; + int n, maxn; + maxn = 0; + n = 0; + for (r = 0; r < 32; r++) + for (g = 0; g < 32; g++) { + color = 512; + for (b = 0; b < 32; b++) + if (color != table[r][g][b]) { + if (maxn < n) + maxn = n; + color = table[r][g][b]; + n = 0; + } else + n++; + } + *blue = (maxn) * 8; + maxn = 0; + n = 0; + for (b = 0; b < 32; b++) + for (g = 0; g < 32; g++) { + color = 512; + for (r = 0; r < 32; r++) + if (color != table[r][g][b]) { + if (maxn < n) + maxn = n; + color = table[r][g][b]; + n = 0; + } else + n++; + } + *red = (maxn) * 8; + maxn = 0; + n = 0; + for (b = 0; b < 32; b++) + for (r = 0; r < 32; r++) { + color = 512; + for (g = 0; g < 32; g++) + if (color != table[r][g][b]) { + if (maxn < n) + maxn = n; + color = table[r][g][b]; + n = 0; + } else + n++; + } + *green = (maxn) * 8; +} +#endif /*FIXEDCOLOR */ +static int initialize(struct filter *f, struct initdata *i) +{ + struct ditherdata *s = (struct ditherdata *) f->data; + struct palette *palette; + int r, g, b; + inhermisc(f, i); + if (i->image->bytesperpixel <= 1) { + int red, green, blue; + if (!inherimage + (f, i, TOUCHIMAGE /*| IMAGEDATA */ , 0, 0, s->palette, 0, 0)) + return 0; + if (!s->active) { + palette = clonepalette(f->image->palette); + restorepalette(s->palette, palette); + destroypalette(palette); + } + switch (f->image->palette->type) { + case C256: + blue = mkrgb(f->image->palette); + red = blue / 256 / 256; + green = (blue / 256) & 255; + blue &= 255; + for (r = 0; r < 32; r++) + for (g = 0; g < 32; g++) + for (b = 0; b < 32; b++) { + s->table[r][g][b] = + f->image->palette-> + pixels[((r * red + red / 2) / 32) + + ((g * green + + green / 2) / 32) * blue * red + + ((b * blue + blue / 2) / 32) * red]; + } + for (r = 0; r < MSIZE; r++) + for (g = 0; g < MSIZE; g++) { + s->rmat[r][g] = + ((int) matrix[r][g] - 128) * 256 / red / 256; + s->gmat[r][g] = + ((int) matrix[(r + 3) % MSIZE][(g + 6) % MSIZE] - + 128) * 256 / green / 256; + s->bmat[r][g] = + ((int) matrix[(r + 6) % MSIZE][(g + 3) % MSIZE] - + 128) * 256 / blue / 256; + } + break; +#ifdef SFIXEDCOLOR + case FIXEDCOLOR: + create_rgb_table(s->table, f->image->palette); + checksizes(s->table, &red, &green, &blue); + for (r = 0; r < MSIZE; r++) + for (g = 0; g < MSIZE; g++) { + s->rmat[r][g] = ((int) matrix[r][g] - 128) * red / 256; + s->gmat[r][g] = + ((int) matrix[(r + 3) % MSIZE][(g + 6) % MSIZE] - + 128) * green / 256; + s->bmat[r][g] = + ((int) matrix[(r + 6) % MSIZE][(g + 3) % MSIZE] - + 128) * blue / 256; + } + break; +#endif +#ifdef BITMAPS + case MBITMAP: + case LBITMAP: + case MIBITMAP: + case LIBITMAP: + break; +#endif + case GRAYSCALE: + break; + default: + x_fatalerror("Unsupported image type. Recompile XaoS."); + } + setfractalpalette(f, s->palette); + s->active = 1; + f->queue->saveimage = f->childimage; + return (f->previous->action->initialize(f->previous, i)); + } else { + if (s->active) { + f->image = i->image; + palette = clonepalette(s->palette); + restorepalette(f->image->palette, palette); + destroypalette(palette); + } + s->active = 0; + return (f->previous->action->initialize(f->previous, i)); + } +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct ditherdata *i = (struct ditherdata *) calloc(1, sizeof(*i)); + i->palette = + createpalette(0, 65536, TRUECOLOR, 0, 65536, NULL, NULL, NULL, + NULL, NULL); + f->data = i; + f->name = "Truecolor to 8bpp convertor"; + return (f); +} + +static void convert(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *RESTRICT f = (struct filter *) data; + struct image *RESTRICT img1 = f->childimage; + struct image *RESTRICT img2 = f->image; + CONST struct ditherdata *RESTRICT s = (struct ditherdata *) f->data; + CONST pixel32_t *RESTRICT src, *srcend; + int r, g, b; + pixel8_t *RESTRICT dest; + int i; + int x = 0; + + for (i = r1; i < r2; i++) { + src = (pixel32_t *) img1->currlines[i]; + dest = img2->currlines[i]; + srcend = src + img1->width; + x++; + x = x & (MSIZE - 1); + for (; src < srcend; src++, dest++) { + b = *src; + g = (b >> 8) & 0xff; + r = (b >> 16); + b &= 0xff; + r += s->rmat[x][(unsigned long) dest & (MSIZE - 1)]; + g += s->gmat[x][(unsigned long) dest & (MSIZE - 1)]; + b += s->bmat[x][(unsigned long) dest & (MSIZE - 1)]; + if (r & (~255)) { + if (r < 0) + r = 0; + else if (r > 255) + r = 255; + } + if (g & (~255)) { + if (g < 0) + g = 0; + else if (g > 255) + g = 255; + } + if (b & (~255)) { + if (b < 0) + b = 0; + else if (b > 255) + b = 255; + } + *dest = s->table[r >> 3][g >> 3][b >> 3]; + } + } +} + +#define intenzity(x) ((int)(((x)&255) * 76 + (((x)>>8)&255) * 151 + (((x)>>16)&255) * 28)>>8) +static void convertgray(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *img1 = f->childimage; + struct image *img2 = f->image; + pixel32_t *src, *srcend; + pixel8_t *dest; + int i; + int x = 0; + unsigned char table[256]; + for (i = 0; i < 256; i++) + table[i] = + i * (img2->palette->end - img2->palette->start) / 256 + + img2->palette->start; + + for (i = r1; i < r2; i++) { + src = (pixel32_t *) img1->currlines[i]; + dest = img2->currlines[i]; + srcend = src + img1->width; + x++; + x = x & (MSIZE - 1); + for (; src < srcend; src++, dest++) { + *dest = table[intenzity(*src)]; + } + } +} + +#ifdef SBITMAPS +#define inten(x) ((int)(((x)&255) * 76 + (((x)>>8)&255) * 151 + (((x)>>16)&255) * 28)>>8)-256 +static void +converttbitmap(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *img1 = f->childimage; + struct image *img2 = f->image; + pixel32_t *src, *srcend; + pixel8_t *dest = NULL; + int i, y; + unsigned int mask = 0; + int x = 0; + unsigned int val = 0; + src = (pixel32_t *) img1->currlines[0]; + for (i = r1; i < r2; i++) { + dest = img2->currlines[i]; + x = i & (MSIZE - 1); + src = (pixel32_t *) img1->currlines[i]; + srcend = src + (img1->width & ~7); + switch (img2->palette->type) { +#ifdef SMBITMAPS + case MBITMAP: + for (; src < srcend; dest++) { + if (inten(src[0]) + (int) matrix[x][0] >= 0) + val = 128; + else + val = 0; + if (inten(src[1]) + (int) matrix[x][1] >= 0) + val |= 64; + if (inten(src[2]) + (int) matrix[x][2] >= 0) + val |= 32; + if (inten(src[3]) + (int) matrix[x][3] >= 0) + val |= 16; + if (inten(src[4]) + (int) matrix[x][4] >= 0) + val |= 8; + if (inten(src[5]) + (int) matrix[x][5] >= 0) + val |= 4; + if (inten(src[6]) + (int) matrix[x][6] >= 0) + val |= 2; + if (inten(src[7]) + (int) matrix[x][7] >= 0) + val |= 1; + src += 8; + *dest = val; + } + srcend = (pixel32_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 128; src < srcend; + mask >>= 1, src++, y++) { + if (inten(*src) + (int) matrix[x][y] >= 0) + val |= mask; + } + if (!mask) + *dest = val, dest++; + } + break; + case MIBITMAP: + for (; src < srcend; dest++) { + if (inten(src[0]) + (int) matrix[x][0] <= 0) + val = 128; + else + val = 0; + if (inten(src[1]) + (int) matrix[x][1] <= 0) + val |= 64; + if (inten(src[2]) + (int) matrix[x][2] <= 0) + val |= 32; + if (inten(src[3]) + (int) matrix[x][3] <= 0) + val |= 16; + if (inten(src[4]) + (int) matrix[x][4] <= 0) + val |= 8; + if (inten(src[5]) + (int) matrix[x][5] <= 0) + val |= 4; + if (inten(src[6]) + (int) matrix[x][6] <= 0) + val |= 2; + if (inten(src[7]) + (int) matrix[x][7] <= 0) + val |= 1; + src += 8; + *dest = val; + } + srcend = (pixel32_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 128; src < srcend; + mask >>= 1, src++, y++) { + if (inten(*src) + (int) matrix[x][y] <= 0) + val |= mask; + } + if (!mask) + *dest = val, dest++; + } + break; +#endif +#ifdef SLBITMAPS + case LBITMAP: + for (; src < srcend; dest++) { + if (inten(src[0]) + (int) matrix[x][0] >= 0) + val = 1; + else + val = 0; + if (inten(src[1]) + (int) matrix[x][1] >= 0) + val |= 2; + if (inten(src[2]) + (int) matrix[x][2] >= 0) + val |= 4; + if (inten(src[3]) + (int) matrix[x][3] >= 0) + val |= 8; + if (inten(src[4]) + (int) matrix[x][4] >= 0) + val |= 16; + if (inten(src[5]) + (int) matrix[x][5] >= 0) + val |= 32; + if (inten(src[6]) + (int) matrix[x][6] >= 0) + val |= 64; + if (inten(src[7]) + (int) matrix[x][7] >= 0) + val |= 128; + src += 8; + *dest = val; + } + srcend = (pixel32_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 1; src < srcend; + mask <<= 1, src++, y++) { + if (inten(*src) + (int) matrix[x][y] >= 0) + val |= mask; + } + if (!mask) + *dest = val, dest++; + } + break; + case LIBITMAP: + for (; src < srcend; dest++) { + if (inten(src[0]) + (int) matrix[x][0] <= 0) + val = 1; + else + val = 0; + if (inten(src[1]) + (int) matrix[x][1] <= 0) + val |= 2; + if (inten(src[2]) + (int) matrix[x][2] <= 0) + val |= 4; + if (inten(src[3]) + (int) matrix[x][3] <= 0) + val |= 8; + if (inten(src[4]) + (int) matrix[x][4] <= 0) + val |= 16; + if (inten(src[5]) + (int) matrix[x][5] <= 0) + val |= 32; + if (inten(src[6]) + (int) matrix[x][6] <= 0) + val |= 64; + if (inten(src[7]) + (int) matrix[x][7] <= 0) + val |= 128; + src += 8; + *dest = val; + } + srcend = (pixel32_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 1; src < srcend; + mask <<= 1, src++, y++) { + if (inten(*src) + (int) matrix[x][y] <= 0) + val |= mask; + } + if (!mask) + *dest = val, dest++; + } + break; +#endif + } + } + *dest = val; +} +#endif +static void destroyinstance(struct filter *f) +{ + struct ditherdata *i = (struct ditherdata *) f->data; + destroypalette(i->palette); + free(f->data); + destroyinheredimage(f); + free(f); +} + +static int doit(struct filter *f, int flags, int time) +{ + int val; + struct ditherdata *s = (struct ditherdata *) f->data; + if (s->active) + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + if (s->active) { +#ifdef SBITMAPS + if (f->image->palette->type & BITMAPS) { + xth_function(converttbitmap, f, f->image->height); + } else +#endif + { + if (f->image->palette->type == GRAYSCALE) + xth_function(convertgray, f, f->image->height); + else + xth_function(convert, f, f->image->height); + } + xth_sync(); + } + return val; +} + +static void myremovefilter(struct filter *f) +{ + struct ditherdata *s = (struct ditherdata *) f->data; + struct palette *palette; + if (s->active) { + palette = clonepalette(s->palette); + restorepalette(f->image->palette, palette); + destroypalette(palette); + } +} + + +CONST struct filteraction truecolor_filter = { + "Truecolor emulator", + "truecolor", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertupgeneric, + convertdowngeneric, + myremovefilter, +}; + + + +#ifdef SCONVERTORS +static int +myfixedalloccolor(struct palette *p, int init, int r, int g, int b) +{ + struct palette *palette = (struct palette *) p->data; + fixedalloccolor(p, init, r, g, b); + return (palette->alloccolor(palette, init, r, g, b)); +} + +static void myallocfinished(struct palette *p) +{ + struct palette *palette = (struct palette *) p->data; + palette->allocfinished(palette); +} + +static void mysetcolor(struct palette *p, int start, int end, rgb_t * rgb) +{ + p->data = &p; +} +#endif +#ifdef SFIXEDCOLOR + +static int initializefixed(struct filter *f, struct initdata *i) +{ + struct fixeddata *s = (struct fixeddata *) f->data; + struct palette *palette; + int r, g; + inhermisc(f, i); + if (i->image->palette->type == FIXEDCOLOR + && !(f->req.supportedmask & FIXEDCOLOR)) { + int red, green, blue; + i->image->palette->alloccolor = myfixedalloccolor; + i->image->palette->allocfinished = myallocfinished; + i->image->palette->data = s->palette; + if (!inherimage + (f, i, TOUCHIMAGE | IMAGEDATA, 0, 0, s->palette, 0, 0)) + return 0; + if (s->active == -1) { + palette = clonepalette(f->image->palette); + restorepalette(s->palette, palette); + destroypalette(palette); + } + create_rgb_table(s->table, f->image->palette); + checksizes(s->table, &red, &green, &blue); + for (r = 0; r < MSIZE; r++) + for (g = 0; g < MSIZE; g++) { + s->rmat[r][g] = ((int) matrix[r][g] - 128) * red / 256; + s->gmat[r][g] = + ((int) matrix[(r + 3) % MSIZE][(g + 6) % MSIZE] - + 128) * green / 256; + s->bmat[r][g] = + ((int) matrix[(r + 6) % MSIZE][(g + 3) % MSIZE] - + 128) * blue / 256; + } + s->palette->data = &s->palette; + setfractalpalette(f, s->palette); + s->active = 1; + f->queue->saveimage = f->childimage; + f->queue->palettechg = f; + return (f->previous->action->initialize(f->previous, i)); + } else { + if (s->active == 1) { + s->fixcolor = 1; + } + s->active = 0; + return (f->previous->action->initialize(f->previous, i)); + } +} + +static struct filter *getinstancefixed(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct fixeddata *i = (struct fixeddata *) calloc(1, sizeof(*i)); + i->palette = + createpalette(0, 256, C256, 0, 256, NULL, mysetcolor, NULL, NULL, + NULL); + i->active = -1; + f->data = i; + f->name = "Palete emulator"; + return (f); +} + +static void convertfixed(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *img1 = f->childimage; + struct image *img2 = f->image; + struct fixeddata *s = (struct fixeddata *) f->data; + pixel8_t *src, *srcend; + pixel8_t *dest; + int i; + int x = 0; + for (i = r1; i < r2; i++) { + src = (pixel8_t *) img1->currlines[i]; + dest = img2->currlines[i]; + srcend = src + img1->width; + x++; + x = x & (MSIZE - 1); + for (; src < srcend; src++, dest++) { + *dest = + s->ctable[x][((unsigned long) dest) & (MSIZE - 1)][*src]; + } + } +} + +static int doitfixed(struct filter *f, int flags, int time) +{ + int val; + struct fixeddata *s = (struct fixeddata *) f->data; + if (s->fixcolor && !s->active) { + struct palette *palette; + s->fixcolor = 0; + palette = clonepalette(s->palette); + restorepalette(f->previous->childimage->palette, palette); + destroypalette(palette); + } + if (s->active) + updateinheredimage(f); + if (!(flags & PALETTEONLY)) + val = f->previous->action->doit(f->previous, flags, time); + else + val = 0; + if (s->active) { + if (s->palette->data != NULL) { + int i, x, y; + s->palette->data = NULL; + val |= CHANGED; + for (i = 0; i < 256; i++) { + for (x = 0; x < 8; x++) + for (y = 0; y < 8; y++) { + int r, g, b; + r = s->palette->rgb[i][0] + s->rmat[x][y]; + if (r & (~255)) { + if (r < 0) + r = 0; + else if (r > 255) + r = 255; + } + g = s->palette->rgb[i][1] + s->gmat[x][y]; + if (g & (~255)) { + if (g < 0) + g = 0; + else if (g > 255) + g = 255; + } + b = s->palette->rgb[i][2] + s->bmat[x][y]; + if (b & (~255)) { + if (b < 0) + b = 0; + else if (b > 255) + b = 255; + } + s->ctable[x][y][i] = + s->table[r >> 3][g >> 3][b >> 3]; + } + } + } + xth_function(convertfixed, f, f->image->height); + xth_sync(); + } + return val; +} + +static void myremovefilterfixed(struct filter *f) +{ + struct fixeddata *s = (struct fixeddata *) f->data; + struct palette *palette; + if (s->active) { + palette = clonepalette(s->palette); + restorepalette(f->image->palette, palette); + destroypalette(palette); + } +} + +static void destroyinstancefixed(struct filter *f) +{ + struct fixeddata *i = (struct fixeddata *) f->data; + destroypalette(i->palette); + free(f->data); + destroyinheredimage(f); + free(f); +} + +CONST struct filteraction fixedcolor_filter = { + "Palette emulator", + "fixedcolor", + 0, + getinstancefixed, + destroyinstancefixed, + doitfixed, + requirement, + initializefixed, + convertupgeneric, + convertdowngeneric, + myremovefilterfixed, +}; +#endif + +#ifdef SBITMAPS +static int initializebitmap(struct filter *f, struct initdata *i) +{ + struct bitmapdata *s = (struct bitmapdata *) f->data; + struct palette *palette; + inhermisc(f, i); + if ((i->image->palette->type & BITMAPS) + && !(f->req.supportedmask & BITMAPS)) { + i->image->palette->alloccolor = myfixedalloccolor; + i->image->palette->allocfinished = myallocfinished; + i->image->palette->data = s->palette; + if (!inherimage + (f, i, TOUCHIMAGE | IMAGEDATA, 0, 0, s->palette, 0, 0)) + return 0; + if (s->active == -1) { + palette = clonepalette(f->image->palette); + restorepalette(s->palette, palette); + destroypalette(palette); + } + s->palette->data = &s->palette; + setfractalpalette(f, s->palette); + s->active = 1; + f->queue->saveimage = f->childimage; + f->queue->palettechg = f; + return (f->previous->action->initialize(f->previous, i)); + } else { + if (s->active == 1) { + s->fixcolor = 1; + } + s->active = 0; + return (f->previous->action->initialize(f->previous, i)); + } +} + +static struct filter *getinstancebitmap(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct bitmapdata *i = (struct bitmapdata *) calloc(1, sizeof(*i)); + i->palette = + createpalette(0, 256, C256, 0, 256, NULL, mysetcolor, NULL, NULL, + NULL); + i->active = -1; + f->data = i; + f->name = "Palete emulator"; + return (f); +} + +#define INTENSITY(r,g,b) (r * 30U + g * 59U + b * 11U)/100U-256U +static void +convertbitmap(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + struct image *img1 = f->childimage; + struct image *img2 = f->image; + struct bitmapdata *s = (struct bitmapdata *) f->data; + pixel8_t *src, *srcend; + pixel8_t *dest = NULL; + int *intensity = s->intensity; + int i; + unsigned int mask = 0; + int x = 0, y; + unsigned int val = 0; + src = (pixel8_t *) img1->currlines[0]; + for (i = r1; i < r2; i++) { + dest = img2->currlines[i]; + x = i & (MSIZE - 1); + src = (pixel8_t *) img1->currlines[i]; + srcend = src + (img1->width & ~7); + switch (img2->palette->type) { +#ifdef SMBITMAPS + case MBITMAP: + for (; src < srcend; dest++) { + if (intensity[src[0]] + (int) matrix[x][0] >= 0) + val = 128; + else + val = 0; + if (intensity[src[1]] + (int) matrix[x][1] >= 0) + val |= 64; + if (intensity[src[2]] + (int) matrix[x][2] >= 0) + val |= 32; + if (intensity[src[3]] + (int) matrix[x][3] >= 0) + val |= 16; + if (intensity[src[4]] + (int) matrix[x][4] >= 0) + val |= 8; + if (intensity[src[5]] + (int) matrix[x][5] >= 0) + val |= 4; + if (intensity[src[6]] + (int) matrix[x][6] >= 0) + val |= 2; + if (intensity[src[7]] + (int) matrix[x][7] >= 0) + val |= 1; + src += 8; + *dest = val; + } + srcend = (pixel8_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 128; src < srcend; + mask >>= 1, src++, y++) { + if (intensity[*src] + (int) matrix[x][y] >= 0) + val |= mask; + } + *dest = val, dest++; + } + break; + case MIBITMAP: + for (; src < srcend; dest++) { + if (intensity[src[0]] + (int) matrix[x][0] <= 0) + val = 128; + else + val = 0; + if (intensity[src[1]] + (int) matrix[x][1] <= 0) + val |= 64; + if (intensity[src[2]] + (int) matrix[x][2] <= 0) + val |= 32; + if (intensity[src[3]] + (int) matrix[x][3] <= 0) + val |= 16; + if (intensity[src[4]] + (int) matrix[x][4] <= 0) + val |= 8; + if (intensity[src[5]] + (int) matrix[x][5] <= 0) + val |= 4; + if (intensity[src[6]] + (int) matrix[x][6] <= 0) + val |= 2; + if (intensity[src[7]] + (int) matrix[x][7] <= 0) + val |= 1; + src += 8; + *dest = val; + } + srcend = (pixel8_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 128; src < srcend; + mask >>= 1, src++, y++) { + if (intensity[*src] + (int) matrix[x][y] <= 0) + val |= mask; + } + *dest = val, dest++; + } + break; +#endif +#ifdef SLBITMAPS + case LBITMAP: + for (; src < srcend; dest++) { + if (intensity[src[0]] + (int) matrix[x][0] >= 0) + val = 1; + else + val = 0; + if (intensity[src[1]] + (int) matrix[x][1] >= 0) + val |= 2; + if (intensity[src[2]] + (int) matrix[x][2] >= 0) + val |= 4; + if (intensity[src[3]] + (int) matrix[x][3] >= 0) + val |= 8; + if (intensity[src[4]] + (int) matrix[x][4] >= 0) + val |= 16; + if (intensity[src[5]] + (int) matrix[x][5] >= 0) + val |= 32; + if (intensity[src[6]] + (int) matrix[x][6] >= 0) + val |= 64; + if (intensity[src[7]] + (int) matrix[x][7] >= 0) + val |= 128; + src += 8; + *dest = val; + } + srcend = (pixel8_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 1; src < srcend; + mask <<= 1, src++, y++) { + if (intensity[*src] + (int) matrix[x][y] >= 0) + val |= mask; + } + *dest = val, dest++; + } + case LIBITMAP: + for (; src < srcend; dest++) { + if (intensity[src[0]] + (int) matrix[x][0] <= 0) + val = 1; + else + val = 0; + if (intensity[src[1]] + (int) matrix[x][1] <= 0) + val |= 2; + if (intensity[src[2]] + (int) matrix[x][2] <= 0) + val |= 4; + if (intensity[src[3]] + (int) matrix[x][3] <= 0) + val |= 8; + if (intensity[src[4]] + (int) matrix[x][4] <= 0) + val |= 16; + if (intensity[src[5]] + (int) matrix[x][5] <= 0) + val |= 32; + if (intensity[src[6]] + (int) matrix[x][6] <= 0) + val |= 64; + if (intensity[src[7]] + (int) matrix[x][7] <= 0) + val |= 128; + src += 8; + *dest = val; + } + srcend = (pixel8_t *) img1->currlines[i] + img1->width; + if (src != srcend) { + y = 0; + for (val = 0, mask = 1; src < srcend; + mask <<= 1, src++, y++) { + if (intensity[*src] + (int) matrix[x][y] <= 0) + val |= mask; + } + *dest = val, dest++; + } + break; +#endif + } + } +} + +static int doitbitmap(struct filter *f, int flags, int time) +{ + int val; + struct bitmapdata *s = (struct bitmapdata *) f->data; + if (s->fixcolor && !s->active) { + struct palette *palette; + s->fixcolor = 0; + palette = clonepalette(s->palette); + restorepalette(f->previous->childimage->palette, palette); + destroypalette(palette); + } + if (s->active) + updateinheredimage(f); + if (!(flags & PALETTEONLY)) + val = f->previous->action->doit(f->previous, flags, time); + else + val = 0; + if (s->active) { + if (s->palette->data != NULL) { + int i; + for (i = 0; i < 256; i++) + s->intensity[i] = + INTENSITY(f->childimage->palette->rgb[i][0], + f->childimage->palette->rgb[i][1], + f->childimage->palette->rgb[i][2]); + val |= CHANGED; + } + xth_function(convertbitmap, f, f->image->height); + xth_sync(); + } + return val; +} + +static void myremovefilterbitmap(struct filter *f) +{ + struct bitmapdata *s = (struct bitmapdata *) f->data; + struct palette *palette; + if (s->active) { + palette = clonepalette(s->palette); + restorepalette(f->image->palette, palette); + destroypalette(palette); + } +} + +static void destroyinstancebitmap(struct filter *f) +{ + struct bitmapdata *i = (struct bitmapdata *) f->data; + destroypalette(i->palette); + free(f->data); + destroyinheredimage(f); + free(f); +} + +CONST struct filteraction bitmap_filter = { + "Palette emulator", + "bitmap", + 0, + getinstancebitmap, + destroyinstancebitmap, + doitbitmap, + requirement, + initializebitmap, + convertupgeneric, + convertdowngeneric, + myremovefilterbitmap, +}; +#endif diff --git a/src/engine/docalc.c b/src/engine/docalc.c new file mode 100644 index 0000000..9cacf27 --- /dev/null +++ b/src/engine/docalc.c @@ -0,0 +1,790 @@ + +/* 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 diff --git a/src/engine/edge.c b/src/engine/edge.c new file mode 100644 index 0000000..09d1403 --- /dev/null +++ b/src/engine/edge.c @@ -0,0 +1,113 @@ +/* An edge detection filter. + * This is very simple filter - it initializes smalliter image and then + * does an simple edge detection algo on it. + */ +#include +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include +#endif +#include /*for NULL */ +#else +#include +#include +#include +#endif +#define SLARGEITER +#include +#include + +#define spixel_t pixel8_t +#include +#define do_edge do_edge8 +#include "edged.c" + +#undef spixel_t +#define spixel_t pixel16_t +#include +#define do_edge do_edge32 +#include "edged.c" + +#include +#define do_edge do_edge24 +#include "edged.c" + +#include +#define do_edge do_edge16 +#include "edged.c" + +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags &= ~IMAGEDATA; + r->supportedmask = MASK1BPP | MASK3BPP | MASK2BPP | MASK4BPP; + return (f->next->action->requirement(f->next, r)); +} + +static int initialize(struct filter *f, struct initdata *i) +{ + inhermisc(f, i); + /*in/out coloring modes looks better in iter modes. This also saves some + memory in truecolor. */ + if (f->data != NULL) + destroypalette((struct palette *) f->data); + f->data = + createpalette(0, 65536, + i->image->bytesperpixel <= 1 ? SMALLITER : LARGEITER, + 0, 65536, NULL, NULL, NULL, NULL, NULL); + if (!inherimage + (f, i, TOUCHIMAGE | NEWIMAGE, 0, 0, (struct palette *) f->data, 0, + 0)) + return 0; + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + f->name = "Edge detection"; + return (f); +} + +static void destroyinstance(struct filter *f) +{ + if (f->data != NULL) + destroypalette((struct palette *) f->data); + destroyinheredimage(f); + free(f); +} + +static int doit(struct filter *f, int flags, int time) +{ + int val; + int size = f->childimage->palette->type == SMALLITER ? 240 : 65520; + if (f->image->palette->size < size) + size = f->image->palette->size; + if (((struct palette *) f->data)->size != size) + ((struct palette *) f->data)->size = + size, ((struct palette *) f->data)->version++; + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + drivercall(*f->image, + xth_function(do_edge8, f, f->image->height), + xth_function(do_edge16, f, f->image->height), + xth_function(do_edge24, f, f->image->height), + xth_function(do_edge32, f, f->image->height)); + xth_sync(); + return val; +} + +CONST struct filteraction edge_filter = { + "Edge detection", + "edge", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertupgeneric, + convertdowngeneric, + NULL +}; diff --git a/src/engine/edge2.c b/src/engine/edge2.c new file mode 100644 index 0000000..fbfeab5 --- /dev/null +++ b/src/engine/edge2.c @@ -0,0 +1,113 @@ +/* An edge detection filter. + * This is very simple filter - it initializes smalliter image and then + * does an simple edge detection algo on it. + */ +#include +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include +#endif +#include /*for NULL */ +#else +#include +#include +#include +#endif +#define SLARGEITER +#include +#include + +#define spixel_t pixel8_t +#include +#define do_edge do_edge8 +#include "edge2d.c" + +#undef spixel_t +#define spixel_t pixel16_t +#include +#define do_edge do_edge32 +#include "edge2d.c" + +#include +#define do_edge do_edge24 +#include "edge2d.c" + +#include +#define do_edge do_edge16 +#include "edge2d.c" + +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags &= ~IMAGEDATA; + r->supportedmask = MASK1BPP | MASK2BPP | MASK3BPP | MASK4BPP; + return (f->next->action->requirement(f->next, r)); +} + +static int initialize(struct filter *f, struct initdata *i) +{ + inhermisc(f, i); + /*in/out coloring modes looks better in iter modes. This also saves some + memory in truecolor. */ + if (f->data != NULL) + destroypalette((struct palette *) f->data); + f->data = + createpalette(0, 65536, + i->image->bytesperpixel <= 1 ? SMALLITER : LARGEITER, + 0, 65536, NULL, NULL, NULL, NULL, NULL); + if (!inherimage + (f, i, TOUCHIMAGE | NEWIMAGE, 0, 0, (struct palette *) f->data, 0, + 0)) + return 0; + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + f->name = "Edge detection"; + return (f); +} + +static void destroyinstance(struct filter *f) +{ + if (f->data != NULL) + destroypalette((struct palette *) f->data); + destroyinheredimage(f); + free(f); +} + +static int doit(struct filter *f, int flags, int time) +{ + int val; + int size = f->childimage->palette->type == SMALLITER ? 253 : 65536; + if (f->image->palette->size < size) + size = f->image->palette->size; + if (((struct palette *) f->data)->size != size) + ((struct palette *) f->data)->size = + size, ((struct palette *) f->data)->version++; + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + drivercall(*f->image, + xth_function(do_edge8, f, f->image->height), + xth_function(do_edge16, f, f->image->height), + xth_function(do_edge24, f, f->image->height), + xth_function(do_edge32, f, f->image->height)); + xth_sync(); + return val; +} + +CONST struct filteraction edge2_filter = { + "Edge detection2", + "edge2", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertupgeneric, + convertdowngeneric, + NULL +}; diff --git a/src/engine/edge2d.c b/src/engine/edge2d.c new file mode 100644 index 0000000..4402b42 --- /dev/null +++ b/src/engine/edge2d.c @@ -0,0 +1,53 @@ +#ifndef UNSUPPORTED +static void do_edge(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + int y; + unsigned int *pixels = f->image->palette->pixels; + register unsigned int black = f->image->palette->pixels[0]; + register cpixel_t *output, *end; + register spixel_t *up, *down, *input; + + for (y = r1; y < r2; y++) { + output = p_add(((cpixel_t *) f->image->currlines[y]), 1); + input = ((spixel_t *) f->childimage->currlines[y]) + 1; + + if (y != 0) + up = ((spixel_t *) f->childimage->currlines[y - 1]) + 1; + else + up = ((spixel_t *) f->childimage->currlines[y]) + 1; + + if (y != f->image->height - 1) + down = ((spixel_t *) f->childimage->currlines[y + 1]) + 1; + else + down = ((spixel_t *) f->childimage->currlines[y]) + 1; + + end = + p_add(((cpixel_t *) f->image->currlines[y]), + f->image->width - 1); + p_setp(output, -1, 0); + p_setp(output, f->image->width - 2, 0); + + while (output < end) { + if (input[0] > up[0] || input[0] > down[0]) { + p_set(output, pixels[input[0]]); + } else if (input[0] != input[1]) { + if (input[0] < input[1]) { + p_set(output, black); + p_inc(output, 1); + input++; + up++; + down++; + } + p_set(output, pixels[input[0]]); + } else + p_set(output, black); + p_inc(output, 1); + input++; + up++; + down++; + } + } +} +#endif +#undef do_edge diff --git a/src/engine/edged.c b/src/engine/edged.c new file mode 100644 index 0000000..918f308 --- /dev/null +++ b/src/engine/edged.c @@ -0,0 +1,66 @@ +#ifndef UNSUPPORTED +static void do_edge(void *data, struct taskinfo *task, int r1, int r2) +{ + struct filter *f = (struct filter *) data; + int y; + unsigned int *pixels = f->image->palette->pixels; + register unsigned int black = f->image->palette->pixels[0]; + register cpixel_t *output, *end; + register spixel_t *up, *down, *input; + for (y = r1; y < r2; y++) { + output = p_add(((cpixel_t *) f->image->currlines[y]), 1); + input = ((spixel_t *) f->childimage->currlines[y]) + 1; + if (y != 0) + up = ((spixel_t *) f->childimage->currlines[y - 1]) + 2; + else + up = ((spixel_t *) f->childimage->currlines[y]) + 2; + if (y != f->image->height - 1) + down = ((spixel_t *) f->childimage->currlines[y + 1]) + 2; + else + down = ((spixel_t *) f->childimage->currlines[y]) + 2; + end = + p_add(((cpixel_t *) f->image->currlines[y]), + f->image->width - 1); + p_setp(output, -1, 0); + p_setp(output, f->image->width - 2, 0); + while (output < end) { + if (input[1] != input[0] || input[0] != up[0] + || input[0] != down[0]) { + if (output < end - 2) { + p_set(output, pixels[input[0]]); + p_setp(output, 1, pixels[input[1]]); + p_setp(output, 2, pixels[input[2]]); + p_inc(output, 3); + input += 3; + up += 3; + down += 3; + while (output < end - 1 + && (input[0] != up[-1] || input[0] != down[-1])) + { + p_set(output, pixels[input[0]]); + p_setp(output, 1, pixels[input[1]]); + p_inc(output, 2); + input += 2; + up += 2; + down += 2; + } + if (output < end + && (input[-1] != input[0] || up[-2] != input[0] + || down[-2] != input[0])) { + p_set(output, pixels[input[0]]); + p_inc(output, 1); + input++; + up++; + down++; + } + } else + p_set(output, pixels[*input]), p_inc(output, 1), + input++, up++, down++; + } else + p_set(output, black), p_inc(output, 1), input++, up++, + down++; + } + } +} +#endif +#undef do_edge diff --git a/src/engine/emboss.c b/src/engine/emboss.c new file mode 100644 index 0000000..f5bef92 --- /dev/null +++ b/src/engine/emboss.c @@ -0,0 +1,266 @@ +#include +#ifndef _plan9_ +#ifdef NO_MALLOC_H +#include +#else +#include +#endif +#include +#else +#include +#include +#include +#endif +#include +#include +#include +struct embossdata { + struct palette *savedpalette, *palette; + int xdist, ydist; + unsigned int table[512]; +}; +static int requirement(struct filter *f, struct requirements *r) +{ + f->req = *r; + r->nimages = 1; + r->flags &= ~(IMAGEDATA); + r->supportedmask = + GRAYSCALE | C256 | TRUECOLOR24 | TRUECOLOR | TRUECOLOR16; + + return (f->next->action->requirement(f->next, r)); +} + +static int initialize(struct filter *f, struct initdata *i) +{ + int x; + struct embossdata *s = (struct embossdata *) f->data; + inhermisc(f, i); + s->palette->size = 256 / 32; + for (x = 0; x < 256 / 32; x++) + s->palette->pixels[x] = x * 32; +#define SSTEP (32*8/64) +#define SSTEP2 (32*8/256) + if (datalost(f, i) || i->image->version != f->imageversion) { + if (s->savedpalette == NULL) + s->savedpalette = clonepalette(i->image->palette); + mkgraypalette(i->image->palette); + if (i->image->palette->type & (C256 | GRAYSCALE)) { + for (x = 0; x < 256; x++) { + int dist = (x + SSTEP - 1) / SSTEP; + dist += 32; + if (dist > 63) + dist = 63; + s->table[x] = i->image->palette->pixels[dist]; + } + for (x = 256; x < 512; x++) { + int dist = -(512 - x + SSTEP - 1) / SSTEP; + dist += 32; + if (dist < 0) + dist = 0; + s->table[x] = i->image->palette->pixels[dist]; + } + } else { + for (x = 0; x < 256; x++) { + int dist = (x + SSTEP2 - 1) / SSTEP2; + dist += 128; + if (dist > 255) + dist = 255; + s->table[x] = + ((dist >> i->image->palette->info.truec. + rprec) << i->image->palette->info.truec. + rshift) | ((dist >> i->image->palette->info. + truec.gprec) << i->image->palette-> + info.truec. + gshift) | ((dist >> + i->image->palette->info.truec.bprec) + << + i->image->palette->info.truec.bshift); + + } + for (x = 256; x < 512; x++) { + int dist = -(512 - x + SSTEP2 - 1) / SSTEP2; + dist += 128; + if (dist < 0) + dist = 0; + s->table[x] = + ((dist >> i->image->palette->info.truec. + rprec) << i->image->palette->info.truec. + rshift) | ((dist >> i->image->palette->info. + truec.gprec) << i->image->palette-> + info.truec. + gshift) | ((dist >> + i->image->palette->info.truec.bprec) + << + i->image->palette->info.truec.bshift); + } + } + } + s->xdist = (int) (0.1 / i->image->pixelwidth); + s->ydist = (int) (0.1 / i->image->pixelwidth); + if (s->xdist < 1) + s->xdist = 1; + if (s->ydist < 1) + s->ydist = 1; + if (!inherimage + (f, i, TOUCHIMAGE, i->image->width + s->xdist, + i->image->height + s->ydist, s->palette, 0, 0)) + return 0; + clear_image(f->image); + setfractalpalette(f, s->savedpalette); + return (f->previous->action->initialize(f->previous, i)); +} + +static struct filter *getinstance(CONST struct filteraction *a) +{ + struct filter *f = createfilter(a); + struct embossdata *i = (struct embossdata *) calloc(1, sizeof(*i)); + i->savedpalette = NULL; + i->palette = + createpalette(0, 256, GRAYSCALE, 0, 256, NULL, NULL, NULL, NULL, + NULL); + f->childimage = NULL; + f->data = i; + f->name = "Emboss"; + return (f); +} + +static void emboss8(void *data, struct taskinfo *task, int r1, int r2) +{ + pixel8_t *src, *srcend, *src2; + pixel8_t *dest; + struct filter *f = (struct filter *) data; + struct embossdata *s = (struct embossdata *) f->data; + int i; + unsigned int *table = s->table; + for (i = r1; i < r2; i++) { + src = f->childimage->currlines[i]; + src2 = f->childimage->currlines[i + s->ydist] + s->xdist; + srcend = src + f->image->width; + dest = f->image->currlines[i]; + while (src < srcend) { + *dest = table[((int) *src2 - (int) *src) & 511]; + src++; + src2++; + dest++; + } + } +} + +#ifdef SUPPORT16 +static void emboss16(void *data, struct taskinfo *task, int r1, int r2) +{ + pixel8_t *src, *srcend, *src2; + pixel16_t *dest; + struct filter *f = (struct filter *) data; + struct embossdata *s = (struct embossdata *) f->data; + int i; + unsigned int *table = s->table; + for (i = r1; i < r2; i++) { + src = f->childimage->currlines[i]; + src2 = f->childimage->currlines[i + s->ydist] + s->xdist; + srcend = src + f->image->width; + dest = (pixel16_t *) f->image->currlines[i]; + while (src < srcend) { + *dest = table[((int) *src2 - (int) *src) & 511]; + src++; + src2++; + dest++; + } + } +} +#endif +#ifdef STRUECOLOR24 +static void emboss24(void *data, struct taskinfo *task, int r1, int r2) +{ + pixel8_t *src, *srcend, *src2; + pixel8_t *dest; + struct filter *f = (struct filter *) data; + struct embossdata *s = (struct embossdata *) f->data; + int i; + unsigned int *table = s->table; + for (i = r1; i < r2; i++) { + src = f->childimage->currlines[i]; + src2 = f->childimage->currlines[i + s->ydist] + s->xdist; + srcend = src + f->image->width; + dest = (pixel8_t *) f->image->currlines[i]; + while (src < srcend) { + *dest = *(dest + 1) = *(dest + 2) = + table[((int) *src2 - (int) *src) & 511]; + src++; + src2++; + dest += 3; + } + } +} +#endif +static void emboss32(void *data, struct taskinfo *task, int r1, int r2) +{ + pixel8_t *src, *srcend, *src2; + pixel32_t *dest; + struct filter *f = (struct filter *) data; + struct embossdata *s = (struct embossdata *) f->data; + int i; + unsigned int *table = s->table; + for (i = r1; i < r2; i++) { + src = f->childimage->currlines[i]; + src2 = f->childimage->currlines[i + s->ydist] + s->xdist; + srcend = src + f->image->width; + dest = (pixel32_t *) f->image->currlines[i]; + while (src < srcend) { + *dest = table[((int) *src2 - (int) *src) & 511]; + src++; + src2++; + dest++; + } + } +} + +static void destroyinstance(struct filter *f) +{ + struct embossdata *i = (struct embossdata *) f->data; + if (i->savedpalette != NULL) + destroypalette(i->savedpalette); + destroypalette(i->palette); + destroyinheredimage(f); + free(f->data); + free(f); +} + +static int doit(struct filter *f, int flags, int time1) +{ + int val; + int time = time1; + updateinheredimage(f); + val = f->previous->action->doit(f->previous, flags, time); + drivercall(*f->image, + xth_function(emboss8, f, f->image->height), + xth_function(emboss16, f, f->image->height), + xth_function(emboss24, f, f->image->height), + xth_function(emboss32, f, f->image->height)); + xth_sync(); + return val; +} + +static void myremovefilter(struct filter *f) +{ + struct embossdata *s = (struct embossdata *) f->data; + if (s->savedpalette != NULL) { + restorepalette(f->image->palette, s->savedpalette); + destroypalette(s->savedpalette); + s->savedpalette = NULL; + } +} + +CONST struct filteraction emboss_filter = { + "Emboss", + "emboss", + 0, + getinstance, + destroyinstance, + doit, + requirement, + initialize, + convertupgeneric, + convertdowngeneric, + myremovefilter +}; diff --git a/src/engine/engine.pri b/src/engine/engine.pri new file mode 100644 index 0000000..1be3f0f --- /dev/null +++ b/src/engine/engine.pri @@ -0,0 +1,35 @@ +SOURCES += \ + $$PWD/formulas.c \ + $$PWD/fractal.c \ + $$PWD/btrace.c \ + $$PWD/palettef.c \ + $$PWD/emboss.c \ + $$PWD/star.c \ + $$PWD/anti.c \ + $$PWD/dither.c \ + $$PWD/edge.c \ + $$PWD/edge2.c \ + $$PWD/rotate.c \ + $$PWD/zoom.c \ + $$PWD/blur.c \ + $$PWD/interlace.c \ + $$PWD/itersmall.c \ + $$PWD/stereogram.c \ + $$PWD/3d.c \ + $$PWD/subwindow.c \ + $$PWD/plane.c \ + $$PWD/julia.c \ + $$PWD/i386.c + +OTHER_FILES += \ + $$PWD/3dd.c \ + $$PWD/btraced.c \ + $$PWD/docalc.c \ + $$PWD/edged.c \ + $$PWD/edge2d.c \ + $$PWD/docalc.c \ + $$PWD/paletted.c \ + $$PWD/rotated.c \ + $$PWD/stard.c \ + $$PWD/stereod.c \ + $$PWD/zoomd.c diff --git a/src/engine/formulas.c b/src/engine/formulas.c new file mode 100644 index 0000000..239ff10 --- /dev/null +++ b/src/engine/formulas.c @@ -0,0 +1,3038 @@ +/* + * 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. + */ +#ifdef _plan9_ +#include +#include +#include +#else +/* Hello reader! + * code you are looking at is dangerous for both you and your hardware! PLEASE + * CLOSE THIS FILE UNLESS YOU REALY KNOW WHAT YOU ARE DOING. + * + * Main purpose of this file is to generate optimal caluclation loops for + * various formulas/algorithms. It heavily includes docalc.c - set of + * caluclation loops, that then uses macros instad of formulas. This lets me + * to change calculation loops easily. At the other hand it looks very ugly. + * You have been warned :) + */ + +// Some help can be read below about line 700. :-) + + +#ifndef _MAC +#include +#endif + +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include +#include +#ifdef __EMX__ +#include +#endif +#include +#endif /*plan9 */ +#include +#include +#include +#include +#include +#include "julia.h" +#include +#ifndef M_PI +#define M_PI 3.1415 +#endif + +#ifdef SLOWFUNCPTR +#define FUNCTYPE INLINE +#else +#define FUNCTYPE +#endif + +#ifdef SFFE_USING +#include "sffe.h" + +extern struct uih_context *globaluih; // to be able to use sffe parser +#endif + +CONST char *CONST incolorname[] = { + "0", + "zmag", + "Decomposition-like", + "real/imag", + "abs(abs(c)-abs(r))", + "cos(mag)", + "mag*cos(real^2)", + "sin(real^2-imag^2)", + "atan(real*imag*creal*cimag)", + "squares", + "True-color", + NULL +}; + +CONST char *CONST outcolorname[] = { + "iter", + "iter+real", + "iter+imag", + "iter+real/imag", + "iter+real+imag+real/imag", + "binary decomposition", + "biomorphs", + "potential", + "color decomposition", + "smooth", + "True-color", + NULL +}; + +CONST char *CONST tcolorname[] = { + "black", + "re*im sin(re^2) angle", + "sin(re) sin(im) sin(square)", + "hsv", + "hsv2", + "cos(re^c) cos(im^2) cos(square)", + "abs(re^2) abs(im^2) abs(square)", + "re*im re*re im*im", + "abs(im*cim) abs(re*cre) abs(re*cim)", + "abs(re*im-csqr) abs(re^2-csqr) abs(im^2-csqr)", + "angle angle2 angle", + "Disable truecolor colouring", + "simple red (for education purposes)", + "simple blue (for education purposes)", + NULL +}; + +#define SHIFT 8 +#define SMUL 256 + +#define __GNUC__EGCS +/* i386 fp comparsions are incredibly slow. We get much better results when we + do it in integer unit. This trick works well for numbers>0*/ +#ifdef __GNUC__EGCS +#ifdef __i386__121 + +/* Use union to be alias-analysis correct. */ +typedef union { + unsigned int *i; + float *f; +} fpint; +#define less_than_4(x) ({float tmp=(x); fpint ptr; ptr.f=&tmp;*ptr.i<0x40800000U;}) +#define less_than_0(x) ({float tmp=(x); fpint ptr; ptr.f=&tmp;*ptr.i&0x80000000U;}) +#define greater_then_1Em6(x) ({float tmp=(x); fpint ptr; ptr.f=&tmp;*ptr.i>(unsigned int)0x358637bdU;}) +#define abs_less_than(x,y) ({float tmp=(x), tmp2=(y); fpint ptr, ptr2; ptr.f=&tmp; ptr2.f=&tmp2;(*ptr.i&~0x80000000U)<*ptr2.i;}) +#define greater_than(x,y) ({float tmp=(x), tmp2=(y); fpint ptr, ptr2; ptr.f=&tmp; ; ptr2.f=&tmp2;*ptr.i>*ptr2.i;}) +#endif +#endif +#ifndef less_than_4 +#define less_than_0(x) ((x)<0) +#define less_than_4(x) ((x)1E-6) +#define abs_less_than(x,y) (myabs(x)(y)) +#endif + + + +#define PERIINOUTPUT() STAT(nperi++;ninside2++);return(cpalette.pixels[0]) + +#define OUTOUTPUT() STAT(niter2+=iter);return(!cfractalc.coloringmode?cpalette.pixels[(iter%(cpalette.size-1))+1]:color_output(zre,zim,iter)) +#define INOUTPUT() STAT(niter1+=iter;ninside2++);return(cfractalc.incoloringmode?incolor_output(zre,zim,pre,pim,iter):cpalette.pixels[0]) + +#define OUTPUT() if(iter>=(unsigned int)cfractalc.maxiter)\ + { \ + if(cfractalc.incoloringmode==10) return(truecolor_output(zre,zim,pre,pim,cfractalc.intcolor,1)); \ + INOUTPUT(); \ + } \ + else { \ + if(cfractalc.coloringmode==10) return(truecolor_output(zre,zim,pre,pim,cfractalc.outtcolor,0)); \ + OUTOUTPUT(); \ + } + +#define SMOOTHOUTPUT() {PRESMOOTH;zre+=0.000001;szmag+=0.000001; \ + iter=(int)(((cfractalc.maxiter-iter)*256+log((double)(cfractalc.bailout/(szmag)))/log((double)((zre)/(szmag)))*256)); \ + if (iter < 0) {\ + iter = (((unsigned int)(cpalette.size - 1)) << 8) - ((-iter) % (((unsigned int)(cpalette.size - 1)) << 8))-1; \ + if (iter < 0) iter=0; \ + } \ + iter %= ((unsigned int)(cpalette.size - 1)) << 8; \ + \ + if ((cpalette.type & (C256 | SMALLITER)) || !(iter & 255)) \ + return (cpalette.pixels[1 + (iter >> 8)]); \ + { \ + unsigned int i1, i2; \ + i1 = cpalette.pixels[1 + (iter >> 8)]; \ + if ((iter >> 8) == (unsigned int)(cpalette.size - 2)) \ + i2 = cpalette.pixels[1]; \ + else \ + i2 = cpalette.pixels[2 + (iter >> 8)]; \ + iter &= 255; \ + return (interpoltype (cpalette, i2, i1, iter)); \ + } \ + } +/* 2009-07-30 JB Langston: + * Fixing bug #3: HSV modes are completely black when compiled with GCC 4... + * Removed CONSTF qualifier from hsv_to_rgb declaration. CONSTF macro is + * defined to __attribute__((__const__)), on which I found some more details + * here: http://unixwiz.net/techtips/gnu-c-attributes.html#const. Apparently + * this should never be used with a function that takes a pointer or relies on + * side-effects, and hsv_to_rgb does both. Therefore, it should never have + * been declared this way in the first place. + */ + +static INLINE void +hsv_to_rgb(int h, int s, int v, int *red, int *green, int *blue) /*CONSTF*/; +static INLINE void +hsv_to_rgb(int h, int s, int v, int *red, int *green, int *blue) +{ + int hue; + int f, p, q, t; + + if (s == 0) { + *red = v; + *green = v; + *blue = v; + } else { + h %= 256; + if (h < 0) + h += 256; + hue = h * 6; + + f = hue & 255; + p = v * (256 - s) / 256; + q = v * (256 - (s * f) / 256) >> 8; + t = v * (256 * 256 - (s * (256 - f))) >> 16; + + switch ((int) (hue / 256)) { + case 0: + *red = v; + *green = t; + *blue = p; + break; + case 1: + *red = q; + *green = v; + *blue = p; + break; + case 2: + *red = p; + *green = v; + *blue = t; + break; + case 3: + *red = p; + *green = q; + *blue = v; + break; + case 4: + *red = t; + *green = p; + *blue = v; + break; + case 5: + *red = v; + *green = p; + *blue = q; + break; + } + } +} + +static unsigned int +truecolor_output(number_t zre, number_t zim, number_t pre, number_t pim, + int mode, int inset) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int +truecolor_output(number_t zre, number_t zim, number_t pre, + number_t pim, int mode, int inset) +{ + /* WARNING: r and b fields are swapped for HISTORICAL REASONS (BUG :), + * in other words: use r for blue and b for red. */ + int r = 0, g = 0, b = 0, w = 0; + + switch (mode) { + case 0: + break; + case 1: + b = (int) ((sin((double) atan2((double) zre, (double) zim) * 20) + + 1) * 127); + w = (int) ((sin((double) zim / zre)) * 127); + r = (int) ((int) (zre * zim)); + g = (int) ((sin((double) (zre * zre) / 2) + 1) * 127); + break; + case 2: + if (!inset) { + r = (int) ((sin((double) zre * 2) + 1) * 127); + g = (int) ((sin((double) zim * 2) + 1) * 127); + b = (int) ((sin((double) (zim * zim + zre * zre) / 2) + + 1) * 127); + } else { + r = (int) ((sin((double) zre * 50) + 1) * 127); + g = (int) ((sin((double) zim * 50) + 1) * 127); + b = (int) ((sin((double) (zim * zim + zre * zre) * 50) + + 1) * 127); + } + w = (int) ((sin((double) zim / zre)) * 127); + break; + case 3: + if (inset) + hsv_to_rgb((int) + (atan2((double) zre, (double) zim) * 256 / M_PI), + (int) ((sin((double) (zre * 50)) + 1) * 128), + (int) ((sin((double) (zim * 50)) + 1) * 128), &r, + &g, &b); + else + hsv_to_rgb((int) + (atan2((double) zre, (double) zim) * 256 / M_PI), + (int) ((sin((double) zre) + 1) * 128), + (int) ((sin((double) zim) + 1) * 128), &r, &g, &b); + break; + case 4: + if (inset) + hsv_to_rgb((int) + (sin((double) (zre * zre + zim * zim) * 0.1) * 256), + (int) (sin(atan2((double) zre, (double) zim) * 10) * + 128 + 128), + (int) ((sin((double) (zre + zim) * 10)) * 65 + 128), + &r, &g, &b); + else + hsv_to_rgb((int) + (sin((double) (zre * zre + zim * zim) * 0.01) * + 256), + (int) (sin(atan2((double) zre, (double) zim) * 10) * + 128 + 128), + (int) ((sin((double) (zre + zim) * 0.3)) * 65 + + 128), &r, &g, &b); + break; + case 5: + { + if (!inset) { + r = (int) (cos((double) myabs(zre * zre)) * 128) + 128; + g = (int) (cos((double) myabs(zre * zim)) * 128) + 128; + b = (int) (cos((double) myabs(zim * zim + zre * zre)) * + 128) + 128; + } else { + r = (int) (cos((double) myabs(zre * zre) * 10) * 128) + + 128; + g = (int) (cos((double) myabs(zre * zim) * 10) * 128) + + 128; + b = (int) (cos((double) myabs(zim * zim + zre * zre) * 10) + * 128) + 128; + } + } + break; + case 6: + { + if (!inset) { + r = (int) (zre * zim * 64); + g = (int) (zre * zre * 64); + b = (int) (zim * zim * 64); + } else + r = (int) (zre * zim * 256); + g = (int) (zre * zre * 256); + b = (int) (zim * zim * 256); + } + break; + case 7: + { + if (!inset) { + r = (int) ((zre * zre + zim * zim - pre * pre - + pim * pim) * 16); + g = (int) ((zre * zre * 2 - pre * pre - pim * pim) * 16); + b = (int) ((zim * zim * 2 - pre * pre - pim * pim) * 16); + } else { + r = (int) ((zre * zre + zim * zim - pre * pre - + pim * pim) * 256); + g = (int) ((zre * zre * 2 - pre * pre - pim * pim) * 256); + b = (int) ((zim * zim * 2 - pre * pre - pim * pim) * 256); + } + } + break; + case 8: + { + if (!inset) { + r = (int) ((myabs(zim * pim)) * 64); + g = (int) ((myabs(zre * pre)) * 64); + b = (int) ((myabs(zre * pim)) * 64); + } else { + r = (int) ((myabs(zim * pim)) * 256); + g = (int) ((myabs(zre * pre)) * 256); + b = (int) ((myabs(zre * pim)) * 256); + } + } + break; + case 9: + { + if (!inset) { + r = (int) ((myabs(zre * zim - pre * pre - pim * pim)) * + 64); + g = (int) ((myabs(zre * zre - pre * pre - pim * pim)) * + 64); + b = (int) ((myabs(zim * zim - pre * pre - pim * pim)) * + 64); + } else { + r = (int) ((myabs(zre * zim - pre * pre - pim * pim)) * + 256); + g = (int) ((myabs(zre * zre - pre * pre - pim * pim)) * + 256); + b = (int) ((myabs(zim * zim - pre * pre - pim * pim)) * + 256); + } + } + break; + case 10: + { + r = (int) (atan2((double) zre, (double) zim) * 128 / M_PI) + + 128; + g = (int) (atan2((double) zre, (double) zim) * 128 / M_PI) + + 128; + b = (int) (atan2((double) zim, (double) zre) * 128 / M_PI) + + 128; + } + break; + // case 11 is for disabling truecolor mode + case 12: + { + b = 255; + g = 0; + r = 0; + w = 50; + } + break; + case 13: + { + r = 255; + g = 0; + b = 0; + w = 0; + } + break; + } + + r += w; + g += w; + b += w; + if (r < 0) + r = 0; + else if (r > 255) + r = 255; + if (g < 0) + g = 0; + else if (g > 255) + g = 255; + if (b < 0) + b = 0; + else if (b > 255) + b = 255; + + switch (cpalette.type) { + case GRAYSCALE: + return ((unsigned int) (r * 76 + g * 151 + b * 29) * + (cpalette.end - cpalette.start) >> 16) + cpalette.start; + case TRUECOLOR: + case TRUECOLOR24: + case TRUECOLOR16: + r >>= cpalette.info.truec.bprec; + g >>= cpalette.info.truec.gprec; + b >>= cpalette.info.truec.rprec; + return ((r << cpalette.info.truec.bshift) + + (g << cpalette.info.truec.gshift) + + (b << cpalette.info.truec.rshift)); + } + + return cpalette.pixels[inset]; +} + +#ifdef __alpha__ +#define __TEST__ +#endif +static unsigned int +color_output(number_t zre, number_t zim, unsigned int iter) +CONSTF REGISTERS(3); +static unsigned int +REGISTERS(3) color_output(number_t zre, number_t zim, unsigned int iter) +{ + int i; + iter <<= SHIFT; + i = iter; + + switch (cfractalc.coloringmode) { + case 9: + break; + case 1: /* real */ + i = (int) (iter + zre * SMUL); + break; + case 2: /* imag */ + i = (int) (iter + zim * SMUL); + break; + case 3: /* real / imag */ +#ifdef __TEST__ + if (zim != 0) +#endif + i = (int) (iter + (zre / zim) * SMUL); + break; + case 4: /* all of the above */ +#ifdef __TEST__ + if (zim != 0) +#endif + i = (int) (iter + (zre + zim + zre / zim) * SMUL); + break; + case 5: + if (zim > 0) + i = ((cfractalc.maxiter << SHIFT) - iter); + break; + case 6: + if (myabs(zim) < 2.0 || myabs(zre) < 2.0) + i = ((cfractalc.maxiter << SHIFT) - iter); + break; + case 7: + zre = zre * zre + zim * zim; +#ifdef __TEST__ + if (zre < 1 || !i) + i = 0; + else +#endif + i = (int) (sqrt(log((double) zre) / i) * 256 * 256); + break; + default: + case 8: + i = (int) ((atan2((double) zre, (double) zim) / (M_PI + M_PI) + + 0.75) * 20000); + break; + } + + if (i < 0) { + i = (((unsigned int) (cpalette.size - 1)) << 8) - + ((-i) % (((unsigned int) (cpalette.size - 1) << 8))) - 1; + if (i < 0) + i = 0; + } + iter = ((unsigned int) i) % ((cpalette.size - 1) << 8); + if ((cpalette.type & (C256 | SMALLITER)) || !(iter & 255)) + return (cpalette.pixels[1 + (iter >> 8)]); + { + unsigned int i1, i2; + + i1 = cpalette.pixels[1 + (iter >> 8)]; + + if ((int) (iter >> 8) == cpalette.size - 2) + i2 = cpalette.pixels[1]; + else + i2 = cpalette.pixels[2 + (iter >> 8)]; + + iter &= 255; + return (interpoltype(cpalette, i2, i1, iter)); + } + +} + +static unsigned int +incolor_output(number_t zre, number_t zim, number_t pre, number_t pim, + unsigned int iter) +CONSTF REGISTERS(3); +REGISTERS(3) +static unsigned int +incolor_output(number_t zre, number_t zim, number_t pre, number_t pim, + unsigned int iter) +{ + int i = iter; + switch (cfractalc.incoloringmode) { + case 1: /* zmag */ + i = (int) (((zre * zre + zim * zim) * + (number_t) (cfractalc.maxiter >> 1) * SMUL + SMUL)); + break; + case 2: /* real */ + i = (int) (((atan2((double) zre, (double) zim) / (M_PI + M_PI) + + 0.75) * 20000)); + break; + default: + break; + case 3: /* real / imag */ + i = (int) (100 + (zre / zim) * SMUL * 10); + break; + case 4: + zre = myabs(zre); + zim = myabs(zim); + pre = myabs(pre); + pre = myabs(pim); + i += (int) (myabs(pre - zre) * 256 * 64); + i += (int) (myabs(pim - zim) * 256 * 64); + break; + case 5: + if (((int) ((zre * zre + zim * zim) * 10)) % 2) + i = (int) (cos((double) (zre * zim * pre * pim)) * 256 * 256); + else + i = (int) (sin((double) (zre * zim * pre * pim)) * 256 * 256); + break; + case 6: + i = (int) ((zre * zre + + zim * zim) * cos((double) (zre * zre)) * 256 * 256); + break; + case 7: + i = (int) (sin((double) (zre * zre - zim * zim)) * 256 * 256); + break; + case 8: + i = (int) (atan((double) (zre * zim * pre * pim)) * 256 * 64); + break; + case 9: + if ((abs((int) (zre * 40)) % 2) ^ (abs((int) (zim * 40)) % 2)) + i = (int) (((atan2((double) zre, (double) zim) / + (M_PI + M_PI) + 0.75) + * 20000)); + else + i = (int) (((atan2((double) zim, (double) zre) / + (M_PI + M_PI) + 0.75) + * 20000)); + break; + }; + + if (i < 0) { + i = (((unsigned int) (cpalette.size - 1)) << 8) - + ((-i) % (((unsigned int) (cpalette.size - 1) << 8))) - 1; + if (i < 0) + i = 0; + } + iter = ((unsigned int) i) % ((cpalette.size - 1) << 8); + + if ((cpalette.type & (C256 | SMALLITER)) || !(iter & 255)) + return (cpalette.pixels[1 + ((unsigned int) iter >> 8)]); + { + unsigned int i1, i2; + i1 = cpalette.pixels[1 + ((unsigned int) iter >> 8)]; + if (((unsigned int) iter >> 8) == + (unsigned int) (cpalette.size - 2)) + i2 = cpalette.pixels[1]; + else + i2 = cpalette.pixels[2 + ((unsigned int) iter >> 8)]; + iter &= 255; + return (interpoltype(cpalette, i2, i1, iter)); + } + +} + +#define VARIABLES +#define INIT +#define UNCOMPRESS +#define USEHACKS +#define PRETEST 0 +#define FORMULA \ + zim=(zim*zre)*2+pim; \ + zre = rp - ip + pre; \ + ip=zim*zim; \ + rp=zre*zre; +#ifdef _NEVER_ +#ifdef __GNUC__ +#ifdef __i386__ +#ifndef NOASSEMBLY +/* The hand optimized internal loops can save extra 9% of CPU speed compared + to latest GCC snapshot. */ + +/* GCC has ugly support for asm statements with fp input/output, so we use + * memory. */ +#define NSFORMULALOOP(iter) \ +{ int tmp; \ +asm( \ +"movl %%edx, %1\n\t" \ +"fldt %9\n\t" \ +"fxch %%st(2)\n\t" \ +"fldt %8\n\t" \ +"fxch %%st(2)\n\t" \ +"fld %%st(0)\n\t" \ +".align 16\n\t" \ +"1:\n\t" \ +"fld %%st(0)\n\t" /* zre zre zim pre pim */ \ +"fxch %%st(2)\n\t" /* zim zre zre ... */ \ +"fmul %%st(0),%%st(2)\n\t" /* zim zre zim*zre */ \ +"movl %1,%%eax\n\t" \ +"fmul %%st(0),%%st(0)\n\t" /* zim*zim zre zim*zre */ \ +"fxch %%st(2)\n\t" /* zim*zre zre zim*zim */ \ +"fadd %%st(0),%%st(0)\n\t" /* 2*zre*zim zre zim*zim */ \ +"fxch %%st(1)\n\t" /* zre 2*zre*zim zim*zim */ \ +"fmul %%st(0),%%st(0)\n\t" /* zre*zre 2*zre*zim zim*zim */ \ +"fxch %%st(1)\n\t" /* 2*zre*zim zre*zre zim*zim */ \ +"fld %%st(2)\n\t" /* zim*zim 2*zre*zim zre*zre zim*zim */ \ +"fsub %%st(4),%%st(0)\n\t" /* zim*zim-pre 2*zre*zim zre*zre zim*zim */ \ +"fxch %%st(3)\n\t" /* zim*zim 2*zre*zim zre*zre zim*zim-pre */ \ +"fadd %%st(2),%%st(0)\n\t" /* zim*zim+zre*zre 2*zre*zim zre*zre zim*zim-pre */ \ +"fxch %%st(1)\n\t" /* 2*zre*zim zim*zim+zre*zre zre*zre zim*zim-pre */ \ +"fadd %%st(5),%%st(0)\n\t" /* 2*zre*zim*pim zim*zim+zre*zre zre*zre zim*zim-pre*/ \ +"fxch %%st(3)\n\t" /* zim*zim-pre zim*zim+zre*zre zre*zre 2*zre*zim+pim */ \ +"fsubp %%st(0),%%st(2)\n\t" /* zim*zim+zre*zre zre*zre-zim*zim+pre 2*zre*zim+pim */ \ +"cmpl %%edx,%%eax\n\t" \ +"ja 2f\n\t" /* cond branch */ \ +"fstps %1\n\t" /* aa-bb+r 2ab+i r i */ \ +"decl %%ecx\n\t" /* */ \ +"jnz 1b\n\t" /* */ \ +"fld %%st(0)\n\t" \ +"2:\n\t" \ +"fstp %%st(0)\n\t" \ +"fstp %%st(2)\n\t" \ +"fstp %%st(2)\n\t" \ +:"=c"(iter),"=m"(tmp),"=&t"(zim),"=&u"(zre) \ +:"d"(0x40800000),"0"(iter),"2"(zre),"3"(zim),"m"(pre),"m"(pim) \ +:"eax","st(2)","st(3)","st(4)","st(5)"); \ +} + +pacalc(long double zre, long double zim, long double pre, long double pim) +{ + int iter = 1000000; + NSFORMULALOOP(iter); + return iter; +} +#endif +#endif +#endif +#endif + +/* Some help for the brave ones. :-) + * + * Mandelbrot's original formula is z=z^2+c which means + * z[next]=z[previous]^2+c. + * Here c is the pixel coordinates from the screen and z[0] is usually 0 + * (if not perturbation was added.) + * In the following code z[previous] is described by (zre;zim) + * and z[next] will also be zre and zim. + * c is described by (pre;pim). + * Finally rp and ip are helper variables, mostly for checking the bailout + * (which usually means abs(z)>=4, see BTEST). + * + * Both basic operations and some other functions (c_mul, c_pow3, ...) can + * be used. For a "detailed" description refer to ../include/complex.h. + * + * If you add/modify fractals, please note that struct formula_formulas + * (at line cca. 1300) should be also edited for proper initialization + * and for menu entries. However it is not self-explanatory, just copy-paste + * existing tables and give it a try. + * + * Finally, please also edit the calculateswitch function and + * the nmformulas constant (at the end of this file). + * + * -- Zoltan, 2009-07-30 + */ + + +#define BTEST less_than_4(rp+ip) +#define SMOOTH +#define SCALC smand_calc +#define SPERI smand_peri +#define CALC mand_calc +#define PERI mand_peri +#define JULIA mand_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#ifdef __i386__ +#define UNCOMPRESS +#endif +#define USEHACKS +#define PRETEST 0 +#define FORMULA \ + rp = zre * (rp - 3 * ip); \ + zim = zim * (3 * zre * zre - ip) + pim; \ + zre = rp + pre; \ + rp = zre * zre; \ + ip = zim * zim; +#define BTEST less_than_4(rp+ip) +#define SMOOTH +#define SCALC smand3_calc +#define SPERI smand3_peri +#define CALC mand3_calc +#define PERI mand3_peri +#define JULIA mand3_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + + +#define UNCOMPRESS +#define VARIABLES number_t br,tmp; +#define FORMULA \ + br = zre + zre + pre - 2; \ + tmp = zre * zim; \ + zre = rp - ip + pre - 1; \ + ip = zim + zim + pim; \ + zim = tmp + tmp + pim; \ + tmp = 1 / (br * br + ip * ip); \ + rp = (zre * br + zim * ip) * tmp; \ + ip = (zim * br - zre * ip) * tmp; \ + zre = (rp + ip) * (rp - ip); \ + zim = rp * ip; \ + zim += zim; \ + rp = zre - 1; \ + ip = zim * zim; \ + rp = zre * zre; +#define BTEST (rp+ip<(number_t)100*100&&(rp-2*zre+ip)>0.04/cfractalc.bailout-1) +#define POSTCALC \ + if(rp-2*zre+ip>0.04/cfractalc.bailout-1){ \ + zre *= 0.08/cfractalc.bailout, zim *= 0.08/cfractalc.bailout; \ + if(iter) \ + iter = cfractalc.maxiter - iter + 1; \ + } +#define CALC magnet_calc +#define PERI magnet_peri +#define SCALC smagnet_calc +#define SPERI smagnet_peri +#define SMOOTH +#define PRESMOOTH szmag/=100*100/4;zre=(rp+ip)/(100*100*4); +#define JULIA magnet_julia +#define RANGE 4 +#define RPIP +#include "docalc.c" + +#define UNCOMPRESS +#define VARIABLES number_t inre,inim,tmp1,tmp2,dnre,nmre,dnim; +#define INIT \ + inre = pre*pre - pim*pim - pre - pre - pre; \ + inim = pre*pim; \ + inim = inim + inim - pim - pim - pim; +#define FORMULA \ + tmp1 = rp - ip; \ + tmp2 = zre*pre - zim*pim - zre; \ + dnre = tmp1 + tmp1 + tmp1 + tmp2 + tmp2 + tmp2 - zre - zre - zre + inre + 3; \ + tmp1 = zre*ip;\ + nmre = zre*rp - tmp1 - tmp1 - tmp1 + tmp2 + tmp2 + tmp2 + inre + 2; \ + tmp1 = zre*zim; \ + tmp2 = zre*pim + zim*pre - zim; \ + dnim = tmp1 + tmp1 + tmp1 + tmp1 + tmp1 + tmp1 + tmp2 + tmp2 + tmp2 - zim - zim - zim + inim; \ + tmp1 = zim*rp; \ + zim = tmp1 + tmp1 + tmp1 - zim*ip + tmp2 + tmp2 + tmp2 + inim; \ + zre = nmre; \ + ip = dnim; \ + tmp1 = 1 / (dnre * dnre + ip * ip); \ + rp = (zre * dnre + zim * ip) * tmp1; \ + ip = (zim * dnre - zre * ip) * tmp1; \ + zre = (rp + ip) * (rp - ip); \ + zim = rp * ip; \ + zim += zim; \ + ip = zim * zim; \ + rp = zre * zre; +#define BTEST (rp+ip<(number_t)100*100&&(rp-2*zre+ip)>0.04/cfractalc.bailout-1) +#define POSTCALC \ + if(rp-2*zre+ip>0.04/cfractalc.bailout-1){ \ + zre *= 0.08/cfractalc.bailout, zim *= 0.08/cfractalc.bailout; \ + if(iter) \ + iter = cfractalc.maxiter - iter + 1; \ + } +#define CALC magnet2_calc +#define PERI magnet2_peri +#define SCALC smagnet2_calc +#define SPERI smagnet2_peri +#define SMOOTH +#define PRESMOOTH szmag/=100*100/4;zre=(rp+ip)/(100*100*4); +#define JULIA magnet2_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#ifdef __i386__ +#define UNCOMPRESS +#endif +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + rp = rp * rp - 6 * rp * ip + ip * ip + pre; \ + zim = 4 * zre * zre * zre * zim - 4 * zre * ip * zim + pim; \ + zre = rp; \ + rp = zre * zre; \ + ip = zim * zim; +#define SMOOTH +#define SCALC smand4_calc +#define SPERI smand4_peri +#define CALC mand4_calc +#define PERI mand4_peri +#define JULIA mand4_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES register number_t t; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + c_pow4(zre, zim, rp, ip); \ + c_mul(zre, zim, rp, ip, t, zim); \ + zre = t + pre; \ + zim += pim; \ + rp = zre * zre; \ + ip = zim * zim; +#define SMOOTH +#define SCALC smand5_calc +#define SPERI smand5_peri +#define CALC mand5_calc +#define PERI mand5_peri +#define JULIA mand5_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + + +#define VARIABLES register number_t t; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + c_pow3(zre, zim, rp, ip); \ + c_mul(rp, ip, rp, ip, t, zim); \ + zre = t + pre; \ + zim += pim; \ + rp = zre * zre; \ + ip = zim * zim; +#define SMOOTH +#define SCALC smand6_calc +#define SPERI smand6_peri +#define CALC mand6_calc +#define PERI mand6_peri +#define JULIA mand6_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + + +#define VARIABLES register number_t t; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + c_pow3(zre, zim, rp, ip); \ + c_pow3(rp, ip, t, zim); \ + zre = t + pre; \ + zim += pim; \ + rp = zre * zre; \ + ip = zim * zim; +#define SMOOTH +#define SCALC smand9_calc +#define SPERI smand9_peri +#define CALC mand9_calc +#define PERI mand9_peri +#define JULIA mand9_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +/* formulas from here to the next comment are not tested under plan9 compiler */ + +#define VARIABLES +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + zim=zre*zim+zim/2+pim; \ + zre=(rp-ip+zre)/2+pre; \ + rp=zre*zre; \ + ip=zim*zim; +#define SMOOTH +#define SCALC strice_calc +#define SPERI strice_peri +#define CALC trice_calc +#define PERI trice_peri +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES register number_t zor,zoi; +/* 2009-08-01 JB Langston + * On Mac OS X, for some reason Cat's Eye renders as an empty circle unless + * the bailout is slightly more than 4. This doesn't appear to happen on any + * other operating systems, and it's not processor specific. It's probably + * a compiler bug, but I haven't been able to figure out exactly what's + * happening. I can work around it by subtracting LDBL_MIN from the amount + * before performing the bailout test. + */ +// #define LDBL_MIN 0.00000001 +#define BTEST less_than_4(rp+ip-LDBL_MIN) +#define FORMULA \ + c_div(pre,pim,zre,zim,rp,ip); \ + c_div(zre,zim,pre,pim,zor,zoi); \ + zre=zor+rp; \ + zim=zoi+ip; \ + rp=zre*zre; \ + ip=zim*zim; +#define SMOOTH +#define SCALC scatseye_calc +#define SPERI scatseye_peri +#define CALC catseye_calc +#define PERI catseye_peri +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + zim=(zim*zre)*(-2.0)+pim; \ + zre=rp-ip+pre; \ + ip=zim*zim; \ + rp=zre*zre; +#define SMOOTH +#define SCALC smbar_calc +#define SPERI smbar_peri +#define CALC mbar_calc +#define PERI mbar_peri +#define JULIA mbar_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT \ + rp=zre;zre=pre;pre=rp; \ + ip=zim;zim=pim;pim=ip; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + rp=ip-rp+zre; \ + ip=zim-2*zre*zim; \ + c_mul(rp,ip,pre,pim,zre,zim); \ + rp=zre*zre; \ + ip=zim*zim; +#define SMOOTH +#define SCALC smlambda_calc +#define SPERI smlambda_peri +#define CALC mlambda_calc +#define PERI mlambda_peri +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES register number_t zre1,zim1,zre2,zim2; +#define INIT zre1=zre;zim1=zim; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + zre2=zre;zim2=zim; \ + zim=(zim*zre)*2+pim+zim1; \ + zre=rp-ip+pre+zre1; \ + zre1=zre2; \ + zim1=zim2; \ + ip=zim*zim; \ + rp=zre*zre; +#define SMOOTH +#define SCALC smanowar_calc +#define CALC manowar_calc +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES register number_t zre1,zim1; +#define INIT zre1=pre;zim1=pim; +#define BTEST less_than_4(rp+ip) +#define FORMULA \ + zim=(zim*zre)*2+zim1; \ + zre=rp-ip+zre1; \ + zre1=zre1/2+zre; \ + zim1=zim1/2+zim; \ + ip=zim*zim; \ + rp=zre*zre; +#define SMOOTH +#define SCALC sspider_calc +#define CALC spider_calc +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT \ + if((zre==pre)&&(zim==pim)){pre=0.5;pim=0.8660254;} \ + if(pim<0)pim=(-pim); \ + if(((pim*zre-pre*zim)<0)||(zim<0)){zre=2*pre+2;zim=2*pim;} +#define BTEST ((pim*zre+(1-pre)*zim)pim)zre=zre-1; \ + if(zim>pim){zim=zim-pim;zre=zre-pre;} +#define CALC sier_calc +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT \ + if((zre==pre)&&(zim==pim)){pre=0.5;pim=0.8660254;} \ + if(pim<0)pim=(-pim); \ + if(((pim*zre-pre*zim)<0)||(zim<0)){zre=2*pre+2;zim=2*pim;} +#define BTEST ((pim*zre+(1-pre)*zim)pim*0.6180339)zre=zre-0.6180339; \ + if(zim>pim*0.6180339){zim=zim-pim*0.6180339;zre=zre-pre*0.6180339;} +#define CALC goldsier_calc +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT +#define BTEST (zre*zre+zim*zim<1) +#define FORMULA \ + zre=3*zre;zim=3*zim; \ + if((zim-2)*(zim-2)+zre*zre<1)zim=zim-2; \ + if((zim+2)*(zim+2)+zre*zre<1)zim=zim+2; \ + if((zim-1)*(zim-1)+(zre-1.7320508)*(zre-1.7320508)<1){zim=zim-1;zre=zre-1.7320508;} \ + if((zim+1)*(zim+1)+(zre-1.7320508)*(zre-1.7320508)<1){zim=zim+1;zre=zre-1.7320508;} \ + if((zim-1)*(zim-1)+(zre+1.7320508)*(zre+1.7320508)<1){zim=zim-1;zre=zre+1.7320508;} \ + if((zim+1)*(zim+1)+(zre+1.7320508)*(zre+1.7320508)<1){zim=zim+1;zre=zre+1.7320508;} +#define CALC circle7_calc +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT +#define BTEST less_than_4((rp+ip)/4.0) +#define FORMULA \ + if (less_than_0 (zre)) { \ + rp = zre + 1; \ + } else { \ + rp = zre - 1; \ + } \ + if (less_than_0 (zim)) { \ + ip = zim + 1; \ + } else { \ + ip = zim - 1; \ + } \ + c_mul(rp, ip, pre, pim, zre, zim); \ + rp = zre * zre; \ + ip = zim * zim; +#define SMOOTH +#define CALC symbarn_calc +#define JULIA symbarn_julia +#define RANGE 2 +#define RPIP +#include "docalc.c" + +#define VARIABLES +#define INIT \ + if((zre==pre)&&(zim==pim)){pre=1;pim=1;} \ + if(pre<0)pre=(-pre);if(pim<0)pim=(-pim); \ + if((zre<0)||(zre>pre)){zre=pre/2;zim=pim/2;} \ + if((zim<0)||(zim>pim)){zre=pre/2;zim=pim/2;} +#define BTEST \ + ((zre
2*pre/3)|| \
+	(zim2*pim/3))
+#define FORMULA \
+	zre=3*zre;zim=3*zim; \
+	if(zre>2*pre)zre=zre-2*pre;else if(zre>pre)zre=zre-pre; \
+	if(zim>2*pim)zim=zim-2*pim;else if(zim>pim)zim=zim-pim;
+#define CALC carpet_calc
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+
+#define VARIABLES
+#define BTEST \
+	((((1.5*zre+0.8660254038*zim)>0.8660254038)|| \
+	((0.8660254038*zim-1.5*zre)>0.8660254038)|| \
+	(zim<(-0.5)))&& \
+	(((1.5*zre+0.8660254038*zim)<-0.8660254038)|| \
+	((0.8660254038*zim-1.5*zre)<-0.8660254038)|| \
+	(zim>0.5)))
+#define FORMULA \
+	zre=3*zre;zim=3*zim; \
+	if((0.2886751346*zim-0.5*zre)>0.0){ \
+		if((0.2886751346*zim+0.5*zre)>0.0){ \
+			zim=zim-2.0;\
+		}else{ \
+			if(zim>0){zre=zre+1.732050808;zim=zim-1.0;} \
+	    		else{zre=zre+1.732050808;zim=zim+1.0;} \
+	    } \
+	}else{ \
+		if((0.2886751346*zim+0.5*zre)<0.0){ \
+			zim=zim+2.0;\
+		}else{ \
+			if(zim>0){zre=zre-1.732050808;zim=zim-1.0;} \
+			else{zre=zre-1.732050808;zim=zim+1.0;} \
+		} \
+	}
+#define CALC koch_calc
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+#define VARIABLES register number_t zre1, zim1;
+#define INIT pim=fabs(pim); zre=pre; zim=pim;
+#define BTEST \
+	(!((zre<0)&&(zim>0)&&(-1.0*zre+1.732050808*zim<1.732050808)))
+#define FORMULA \
+	zre1=1.5*zre-0.866+0.866*zim; \
+	zim1=-1.5+1.5*zim-0.866*zre; \
+	zre=zre1; zim=zim1;
+#define CALC hornflake_calc
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+/* plan9 compiler has problem with rest of formulas files. Hope that will be fixed later */
+
+#define VARIABLES
+#define BTEST less_than_4(rp+ip)
+#define FORMULA \
+	if (less_than_0 (zre)) { \
+	    rp = zre + 1; \
+	} else { \
+	    rp = zre - 1; \
+	} \
+	c_mul(rp, zim, pre, pim, zre, zim); \
+	rp = zre * zre; \
+	ip = zim * zim;
+#define SMOOTH
+#define SCALC sbarnsley1_calc
+#define CALC barnsley1_calc
+#define JULIA barnsley1_julia
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+
+#define VARIABLES
+#define BTEST less_than_4(rp+ip)
+#define FORMULA \
+	if (less_than_0 (zre*pim + zim*pre)) { \
+	    rp = zre + 1; \
+	} else { \
+	    rp = zre - 1; \
+	} \
+	c_mul(rp, zim, pre, pim, zre, zim); \
+	rp = zre * zre; \
+	ip = zim * zim;
+#define SMOOTH
+#define SCALC sbarnsley2_calc
+#define CALC barnsley2_calc
+#define JULIA barnsley2_julia
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+#define VARIABLES
+#define BTEST less_than_4(rp+ip)
+#define FORMULA \
+	if (!less_than_0 (-zre)) { \
+		zim = 2*zre*zim + pim*zre; \
+		zre = rp - ip - 1 + pre*zre; \
+	} else { \
+		zim = 2*zre*zim; \
+		zre = rp - ip - 1; \
+	} \
+	rp = zre * zre; \
+	ip = zim * zim;
+#define SMOOTH
+#define SCALC sbarnsley3_calc
+#define CALC barnsley3_calc
+#define JULIA barnsley3_julia
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+
+#define VARIABLES register number_t n,sqrr,sqri,zre1,zim1;
+#define INIT sqri=zim*zim,n=zre,zre=pre,pre=n,n=zim,zim=pim,pim=n,n=(number_t)1;
+#define BTEST greater_then_1Em6(n)
+#define FORMULA \
+	zre1 = zre; \
+	zim1 = zim; \
+	n = zim * zim; \
+	sqri = zre * zre; \
+	sqrr = sqri - n; \
+	sqri = n + sqri; \
+	n = 0.3333333333 / ((sqri * sqri)); \
+	zim = (0.66666666) * zim - (zre + zre) * zim * n + pim; \
+	zre = (0.66666666) * zre + (sqrr) * n + pre; \
+	zre1 -= zre; \
+	zim1 -= zim; \
+	n = zre1 * zre1 + zim1 * zim1;
+#define CALC newton_calc
+#include "docalc.c"
+
+
+#define VARIABLES register number_t n,sqrr,sqri,zre1,zim1;
+#define INIT sqri=zim*zim,n=zre,zre=pre,pre=n,n=zim,zim=pim,pim=n,n=(number_t)1;
+#define BTEST greater_then_1Em6(n)
+#define FORMULA \
+    zre1 = zre; \
+    zim1 = zim; \
+    sqrr = zre * zre; \
+    sqri = zim * zim; \
+    n = sqri + sqrr; \
+    n = 1 / ((n * n * n)); \
+    zim = (0.25) * zim * (3 + (sqri - 3 * sqrr) * n) + pim; \
+    zre = (0.25) * zre * (3 + (sqrr - 3 * sqri) * n) + pre; \
+    zre1 -= zre; \
+    zim1 -= zim; \
+    n = zre1 * zre1 + zim1 * zim1;
+#define CALC newton4_calc
+#include "docalc.c"
+
+
+#define VARIABLES register number_t zpr,zip;
+#define SAVEVARIABLES register number_t szpr,szip;
+#define SAVE szpr=zpr,szip=zip;
+#define RESTORE zpr=szpr,zip=szip;
+#define INIT zpr=zip=(number_t)0;
+#define BTEST less_than_4(rp+ip)
+#define FORMULA \
+	rp = rp - ip + pre + pim * zpr; \
+	ip = 2 * zre * zim + pim * zip; \
+	zpr = zre, zip = zim; \
+	zre = rp; \
+	zim = ip; \
+	rp = zre * zre, ip = zim * zim;
+#define SMOOTH
+#define SCALC sphoenix_calc
+#define SPERI sphoenix_peri
+#define CALC phoenix_calc
+#define PERI phoenix_peri
+#define RPIP
+#include "docalc.c"
+
+
+#define VARIABLES register number_t tr,ti,zpr,zpm,rp1,ip1;
+#define INIT zpr=zpm=0,tr=zre,zre=pre,pre=tr,tr=zim,zim=pim,pim=tr,tr=1;
+#define BTEST less_than_4(zpr*zpr+zpm*zpm)
+#define FORMULA \
+	rp1 = zre; \
+	ip1 = zim; \
+	c_pow3(zre, zim, tr, ti); \
+	c_add(tr, ti, zpr, zpm, zre, zim); \
+	zpr = rp1 + pre; \
+	zpm = ip1 + pim;
+#define CALC octo_calc
+#define SCALC socto_calc
+#define SMOOTH
+#define CUSTOMSAVEZMAG szmag=zpr*zpr+zpm*zpm
+#define PRESMOOTH zre=zpr*zpr+zpm*zpm
+#include "docalc.c"
+
+
+#define VARIABLES register number_t yre, yim, re1tmp, re2tmp, im1tmp;
+#define BTEST (rp+ip<9||(yre*yre+yim*yim)<4*(rp+ip))
+#define INIT yre=pre; yim=pim;
+#define FORMULA \
+        re1tmp=zre; \
+      	re2tmp=yre; \
+	im1tmp=zim; \
+        zre=re1tmp+yre; \
+	zim=im1tmp+yim; \
+	yre=(re1tmp*re2tmp-im1tmp*yim   ); \
+	yim=(re1tmp*yim   +re2tmp*im1tmp); \
+	rp=zre*zre; \
+	ip=zim*zim;
+#define CALC beryl_calc
+#define JULIA beryl_julia
+#define PERI beryl_peri
+#define RANGE 2
+#define RPIP
+#include "docalc.c"
+
+
+
+#ifdef SFFE_USING
+ /* SFFE - malczak */
+ //#define VARIABLES sffe *p = globaluih->parser; 
+#define INIT cmplxset(pZ,0,0); cmplxset(C,pre,pim); \
+		if (globaluih->pinit) Z=sffe_eval(globaluih->pinit); else cmplxset(Z,zre,zim);
+ //#define SAVE cmplxset(pZ,real(Z),imag(Z));
+ //#define PRETEST 0
+#define FORMULA \
+	 Z = sffe_eval(globaluih->parser);\
+	 cmplxset(pZ,zre,zim); \
+	 zre = real( Z ); \
+	 zim = imag( Z );
+#define BTEST less_than_4(zre*zre+zim*zim)
+ //less_than_4(rp+ip)
+#define CALC sffe_calc
+#define JULIA sffe_julia
+#define SCALC ssffe_calc
+ //#define SMOOTH
+#include "docalc.c"
+#endif
+
+
+static CONST symetrytype sym6[] = {
+    {0, 1.73205080758},
+    {0, -1.73205080758}
+};
+
+static CONST symetrytype sym8[] = {
+    {0, 1},
+    {0, -1}
+};
+
+static CONST symetrytype sym16[] = {
+    {0, 1},
+    {0, -1},
+    {0, 0.414214},
+    {0, -0.414214},
+    {0, 2.414214},
+    {0, -2.414214}
+};
+
+CONST struct formula formulas[] = {
+    {				/* 0 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand_calc,
+     mand_peri,
+     smand_calc,
+     smand_peri,
+#endif
+     mand_julia,
+     {"Mandelbrot", "Julia"},
+     "mandel",
+     /*{0.5, -2.0, 1.25, -1.25}, */
+     {-0.75, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 1 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand3_calc,
+     mand3_peri,
+     smand3_calc,
+     smand3_peri,
+#endif
+     mand3_julia,
+     {"Mandelbrot^3", "Julia^3"},
+     "mandel3",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {0, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 2 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand4_calc,
+     mand4_peri,
+     smand4_calc,
+     smand4_peri,
+#endif
+     mand4_julia,
+     {"Mandelbrot^4", "Julia^4"},
+     "mandel4",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 3 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand5_calc,
+     mand5_peri,
+     smand5_calc,
+     smand5_peri,
+#endif
+     mand5_julia,
+     {"Mandelbrot^5", "Julia^5"},
+     "mandel5",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {0, 0, 2, sym8},
+      {INT_MAX, 0, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {0, 0, 2, sym8},
+      {0, 0, 2, sym8},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 2, sym8},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {0, 0, 2, sym8},
+      {0, 0, 2, sym8},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 4 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand6_calc,
+     mand6_peri,
+     smand6_calc,
+     smand6_peri,
+#endif
+     mand6_julia,
+     {"Mandelbrot^6", "Julia^6"},
+     "mandel6",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 5 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     newton_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Newton", "Newton julia?"},
+     "newton",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     0, 1, 1.0199502202048319698, 0.0,
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO,
+     },
+    {				/* formula added by Andreas Madritsch *//* 6 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     newton4_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Newton^4", "Newton^4 julia?"},
+     "newton4",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     0, 1, 1.0199502202048319698, 0.0,
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO,
+     },
+    {				/* 7 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     barnsley1_calc,
+     NULL,
+     sbarnsley1_calc,
+     NULL,
+#endif
+     barnsley1_julia,
+     {"Barnsley1 Mandelbrot", "Barnsley1"},
+     "barnsley",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     0, 0, -0.6, 1.1,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO | MANDEL_BTRACE,
+     },
+    {				/* formula added by Andreas Madritsch *//* 8 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     barnsley2_calc,
+     NULL,
+     sbarnsley2_calc,
+     NULL,
+#endif
+     barnsley2_julia,
+     {"Barnsley2 Mandelbrot", "Barnsley2"},
+     "barnsley2",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 5.5},
+     0, 0, -0.6, 1.1,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO | MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete *//* 9 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     barnsley3_calc,
+     NULL,
+     sbarnsley3_calc,
+     NULL,
+#endif
+     barnsley3_julia,
+     {"Barnsley3 Mandelbrot", "Barnsley3"},
+     "barnsley3",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 3.5},
+     0, 0, 0.0, 0.4,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO | MANDEL_BTRACE,
+     },
+    {				/* 10 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     octo_calc,
+     /*octo_peri, */ NULL,
+     socto_calc,
+     /*socto_peri, */ NULL,
+#endif
+     NULL,
+     {"Octal", "Octal"},
+     "octal",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     0, 1, 0.0, 0.0,
+     {
+      {0, 0, 6, sym16},
+      {INT_MAX, 0, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {0, 0, 6, sym16},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE | STARTZERO,
+     },
+    {				/* 11 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     phoenix_calc,
+     phoenix_peri,
+     sphoenix_calc,
+     sphoenix_peri,
+#endif
+     NULL,
+     {"MandPhoenix", "Phoenix"},
+     "phoenix",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 0, 0.56667000000000001, -0.5,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* 12 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     magnet_calc,
+     magnet_peri,
+     smagnet_calc,
+     smagnet_peri,
+#endif
+     magnet_julia,
+     {"Magnet", "Magnet"},
+     "magnet",
+     /*{3, 0, 2.2, -2.2}, */
+     {1.5, 0.0, 3.0, 4.4},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO,
+     },
+    {				/* formula added by Andreas Madritsch *//* 13 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     magnet2_calc,
+     magnet2_peri,
+     smagnet2_calc,
+     smagnet2_peri,
+#endif
+     magnet2_julia,
+     {"Magnet2", "Magnet2"},
+     "magnet2",
+     /*{3, 0, 2.2, -2.2}, */
+     {1.0, 0.0, 3.0, 3.2},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     STARTZERO,
+     },
+    {				/* formula added by Arpad Fekete *//* 14 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     trice_calc,
+     trice_peri,
+     strice_calc,
+     strice_peri,
+#endif
+     NULL,
+     {"Triceratops", "Triceratops Julia"},
+     "trice",
+     {0.0, 0.0, 2.5, 4.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete *//* 15 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     catseye_calc,
+     catseye_peri,
+     scatseye_calc,
+     scatseye_peri,
+#endif
+     NULL,
+     {"Catseye", "Catseye Julia"},
+     "catseye",
+     {0.0, 0.0, 2.5, 4.5},
+     1, 1, 0.0, 0.0,
+     {
+      {0, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/*formula added by Arpad Fekete *//* 16 */
+     /*in Gnofract4d from mathworld.wolfram.com */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mbar_calc,
+     mbar_peri,
+     smbar_calc,
+     smbar_peri,
+#endif
+     mbar_julia,
+     {"Mandelbar", "Mandelbar Julia"},
+     "mbar",
+     {0.0, 0.0, 2.5, 3.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, 0, 2, sym6},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete (from fractint) *//* 17 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mlambda_calc,
+     mlambda_peri,
+     smlambda_calc,
+     smlambda_peri,
+#endif
+     NULL,
+     {"Lambda Mandelbrot", "Lambda"},
+     "mlambda",
+     {0.5, 0.0, 2.5, 5.5},
+     0, 0, 0.5, 0.0,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete (from fractint) *//* 18 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     manowar_calc,
+     NULL,
+     smanowar_calc,
+     NULL,
+#endif
+     NULL,
+     {"Manowar", "Manowar Julia"},
+     "manowar",
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete (from fractint) *//* 19 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     spider_calc,
+     NULL,
+     sspider_calc,
+     NULL,
+#endif
+     NULL,
+     {"Spider", "Spider Julia"},
+     "spider",
+     {0.0, 0.0, 2.5, 4.5},
+     1, 1, 0.0, 0.0,
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, 0, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete, method from fractint *//* 20 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     sier_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Sierpinski", "Sierpinski"},
+     "sier",
+     {0.5, 0.43, 1.5, 1.0},
+     0, 0, 0.5, 0.8660254,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete, method from fractint *//* 21 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     carpet_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"S.Carpet", "S.Carpet"},
+     "carpet",
+     {0.5, 0.5, 1.5, 1.5},
+     0, 0, 1, 1,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete, method from fractint *//* 22 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     koch_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Koch Snowflake", "Koch Snowflake"},
+     "koch",
+     {0.0, 0.0, 2.5, 2.5},
+     0, 1, 0, 0,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Z. Kovacs *//* 23 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     hornflake_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Spidron hornflake", "Spidron hornflake"},
+     "hornflake",
+     {-0.75, 0, 3.8756, 3.8756},
+     0, 1, 0, 0,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Z. Kovacs, originally mand6 but it was mand9 by accident *//* 24 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     mand9_calc,
+     mand9_peri,
+     smand9_calc,
+     smand9_peri,
+#endif
+     mand9_julia,
+     {"Mandelbrot^9", "Julia^9"},
+     "mandel9",
+     /*{1.25, -1.25, 1.25, -1.25}, */
+     {0.0, 0.0, 2.5, 2.5},
+     1, 1, 0.0, 0.0,
+     {
+      {0, 0, 6, sym16},
+      {INT_MAX, 0, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, INT_MAX, 0, NULL},
+      {0, 0, 0, NULL},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {0, 0, 6, sym16},
+      {0, 0, 6, sym16},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+     
+   { /* formula added by S. Bizien *//* 25 */
+    FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+   beryl_calc,
+   beryl_peri,
+   NULL,
+   NULL,
+#endif
+   NULL,
+   {"Beryl", "Beryl"},
+   "beryl",
+   {-0.6, 0, 2, 2},
+   0, 0, 1.0, 0.0,
+   {
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    },
+   {
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    {INT_MAX, INT_MAX, 0, NULL},
+    },
+    MANDEL_BTRACE,
+    },   
+    {				/* formula added by Arpad Fekete *//* 26 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     goldsier_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Golden Sierpinski", "Golden Sierpinski"},
+     "goldsier",
+     {0.5, 0.43, 1.5, 1.0},
+     0, 0, 0.5, 0.8660254,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete *//* 27 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     circle7_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     NULL,
+     {"Circle 7", "Circle 7"},
+     "circle7",
+     {0.0, 0.0, 2.5, 2.5},
+     0, 0, 0.0, 0.0,
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     },
+    {				/* formula added by Arpad Fekete *//* 28 */
+     FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+     symbarn_calc,
+     NULL,
+     NULL,
+     NULL,
+#endif
+     symbarn_julia,
+     {"Sym. Barnsley M.", "Sym. Barnsley"},
+     "symbarn",
+     {0.0, 0.0, 8.0, 1.0},
+     0, 0, 1.3, 1.3,
+     /* Arpad hasn't created the symmetry properties, */
+     /* because he doesn't considered it to be important */
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     {
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      {INT_MAX, INT_MAX, 0, NULL},
+      },
+     MANDEL_BTRACE,
+     }
+
+#ifdef SFFE_USING
+    , {				/* formula added by M. Malczak - SFFE *//* 29 */
+       FORMULAMAGIC,
+#ifndef SLOWFUNCPTR
+       sffe_calc,
+       NULL,
+       NULL,
+       NULL,
+#endif
+       sffe_julia,
+       {"User defined", "User defined"},
+       "user",
+       /*{0.5, -2.0, 1.25, -1.25}, */
+	/*{-0.75, 0.0, 1, 1},*/
+	/* 2009-08-01 JB Langston
+	 * Changed default zoom level to match Mandelbrot
+	 */
+	{-0.75, 0.0, 2.5, 2.5},
+	0, 1, 0.0, 0.0,
+       {
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	},
+       {
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	{INT_MAX, INT_MAX, 0, NULL},
+	},
+       MANDEL_BTRACE | SFFE_FRACTAL,
+       }
+#endif
+
+};
+
+#ifdef SLOWFUNCPTR
+unsigned int
+calculateswitch(register number_t x1, register number_t y1,
+		register number_t x2, register number_t y2,
+		int periodicity)
+{
+    if (periodicity && cfractalc.periodicity)
+	if (cfractalc.coloringmode == 9)
+	    switch (cfractalc.currentformula - formulas) {	/* periodicity checking and smoothmode SPERI */
+	    case 0:
+		return (smand_peri(x1, y1, x2, y2));
+		break;
+	    case 1:
+		return (smand3_peri(x1, y1, x2, y2));
+		break;
+	    case 2:
+		return (smand4_peri(x1, y1, x2, y2));
+		break;
+	    case 3:
+		return (smand5_peri(x1, y1, x2, y2));
+		break;
+	    case 4:
+		return (smand6_peri(x1, y1, x2, y2));
+		break;
+	    case 5:
+		return (newton_calc(x1, y1, x2, y2));
+		break;
+	    case 6:
+		return (newton4_calc(x1, y1, x2, y2));
+		break;
+	    case 7:
+		return (sbarnsley1_calc(x1, y1, x2, y2));
+		break;
+	    case 8:
+		return (sbarnsley2_calc(x1, y1, x2, y2));
+		break;
+	    case 9:
+		return (sbarnsley3_calc(x1, y1, x2, y2));
+		break;
+	    case 10:
+		return (octo_calc(x1, y1, x2, y2));
+		break;
+	    case 11:
+		return (sphoenix_peri(x1, y1, x2, y2));
+		break;
+	    case 12:
+		return (smagnet_peri(x1, y1, x2, y2));
+		break;
+	    case 13:
+		return (smagnet2_peri(x1, y1, x2, y2));
+		break;
+	    case 14:
+		return (strice_peri(x1, y1, x2, y2));
+		break;
+	    case 15:
+		return (scatseye_peri(x1, y1, x2, y2));
+		break;
+	    case 16:
+		return (smbar_peri(x1, y1, x2, y2));
+		break;
+	    case 17:
+		return (smlambda_peri(x1, y1, x2, y2));
+		break;
+	    case 18:
+		return (smanowar_calc(x1, y1, x2, y2));
+		break;
+	    case 19:
+		return (sspider_calc(x1, y1, x2, y2));
+		break;
+	    case 20:
+		return (sier_calc(x1, y1, x2, y2));
+		break;
+	    case 21:
+		return (carpet_calc(x1, y1, x2, y2));
+		break;
+	    case 22:
+		return (koch_calc(x1, y1, x2, y2));
+		break;
+	    case 23:
+		return (hornflake_calc(x1, y1, x2, y2));
+		break;
+	    case 24:
+		return (smand9_peri(x1, y1, x2, y2));
+		break;
+	    case 25:
+		return (beryl_calc(x1, y1, x2, y2));
+		break;
+            case 26:
+		return (goldsier_calc(x1, y1, x2, y2));
+		break;
+            case 27:
+		return (circle7_calc(x1, y1, x2, y2));
+		break;
+            case 28:
+		return (symbarn_calc(x1, y1, x2, y2));
+		break;
+		
+#ifdef SFFE_USING
+	    case 29:
+		return (sffe_calc(x1, y1, x2, y2));
+		break;
+#endif
+	} else
+	    switch (cfractalc.currentformula - formulas) {	/* periodicity checking and no smoothmode PERI */
+	    case 0:
+		return (mand_peri(x1, y1, x2, y2));
+		break;
+	    case 1:
+		return (mand3_peri(x1, y1, x2, y2));
+		break;
+	    case 2:
+		return (mand4_peri(x1, y1, x2, y2));
+		break;
+	    case 3:
+		return (mand5_peri(x1, y1, x2, y2));
+		break;
+	    case 4:
+		return (mand6_peri(x1, y1, x2, y2));
+		break;
+	    case 5:
+		return (newton_calc(x1, y1, x2, y2));
+		break;
+	    case 6:
+		return (newton4_calc(x1, y1, x2, y2));
+		break;
+	    case 7:
+		return (barnsley1_calc(x1, y1, x2, y2));
+		break;
+	    case 8:
+		return (barnsley2_calc(x1, y1, x2, y2));
+		break;
+	    case 9:
+		return (barnsley3_calc(x1, y1, x2, y2));
+		break;
+	    case 10:
+		return (octo_calc(x1, y1, x2, y2));
+		break;
+	    case 11:
+		return (phoenix_peri(x1, y1, x2, y2));
+		break;
+	    case 12:
+		return (magnet_peri(x1, y1, x2, y2));
+		break;
+	    case 13:
+		return (magnet2_peri(x1, y1, x2, y2));
+		break;
+	    case 14:
+		return (trice_peri(x1, y1, x2, y2));
+		break;
+	    case 15:
+		return (catseye_peri(x1, y1, x2, y2));
+		break;
+	    case 16:
+		return (mbar_peri(x1, y1, x2, y2));
+		break;
+	    case 17:
+		return (mlambda_peri(x1, y1, x2, y2));
+		break;
+	    case 18:
+		return (manowar_calc(x1, y1, x2, y2));
+		break;
+	    case 19:
+		return (spider_calc(x1, y1, x2, y2));
+		break;
+	    case 20:
+		return (sier_calc(x1, y1, x2, y2));
+		break;
+	    case 21:
+		return (carpet_calc(x1, y1, x2, y2));
+		break;
+	    case 22:
+		return (koch_calc(x1, y1, x2, y2));
+		break;
+	    case 23:
+		return (hornflake_calc(x1, y1, x2, y2));
+		break;
+	    case 24:
+		return (mand9_peri(x1, y1, x2, y2));
+		break;
+	    case 25:
+		return (beryl_peri(x1, y1, x2, y2));
+		break;
+            case 26:
+		return (goldsier_calc(x1, y1, x2, y2));
+		break;
+            case 27:
+		return (circle7_calc(x1, y1, x2, y2));
+		break;
+            case 28:
+		return (symbarn_calc(x1, y1, x2, y2));
+		break;
+		
+#ifdef SFFE_USING
+	    case 29:
+		return (sffe_calc(x1, y1, x2, y2));
+		break;
+#endif
+    } else if (cfractalc.coloringmode == 9)
+	switch (cfractalc.currentformula - formulas) {	/* no periodicity checking and smoothmode SCALC */
+	case 0:
+	    return (smand_calc(x1, y1, x2, y2));
+	    break;
+	case 1:
+	    return (smand3_calc(x1, y1, x2, y2));
+	    break;
+	case 2:
+	    return (smand4_calc(x1, y1, x2, y2));
+	    break;
+	case 3:
+	    return (smand5_calc(x1, y1, x2, y2));
+	    break;
+	case 4:
+	    return (smand6_calc(x1, y1, x2, y2));
+	    break;
+	case 5:
+	    return (newton_calc(x1, y1, x2, y2));
+	    break;
+	case 6:
+	    return (newton4_calc(x1, y1, x2, y2));
+	    break;
+	case 7:
+	    return (sbarnsley1_calc(x1, y1, x2, y2));
+	    break;
+	case 8:
+	    return (sbarnsley2_calc(x1, y1, x2, y2));
+	    break;
+	case 9:
+	    return (sbarnsley3_calc(x1, y1, x2, y2));
+	    break;
+	case 10:
+	    return (socto_calc(x1, y1, x2, y2));
+	    break;
+	case 11:
+	    return (sphoenix_calc(x1, y1, x2, y2));
+	    break;
+	case 12:
+	    return (smagnet_calc(x1, y1, x2, y2));
+	    break;
+	case 13:
+	    return (smagnet2_calc(x1, y1, x2, y2));
+	    break;
+	case 14:
+	    return (strice_calc(x1, y1, x2, y2));
+	    break;
+	case 15:
+	    return (scatseye_calc(x1, y1, x2, y2));
+	    break;
+	case 16:
+	    return (smbar_calc(x1, y1, x2, y2));
+	    break;
+	case 17:
+	    return (smlambda_calc(x1, y1, x2, y2));
+	    break;
+	case 18:
+	    return (smanowar_calc(x1, y1, x2, y2));
+	    break;
+	case 19:
+	    return (sspider_calc(x1, y1, x2, y2));
+	    break;
+	case 20:
+	    return (sier_calc(x1, y1, x2, y2));
+	    break;
+	case 21:
+	    return (carpet_calc(x1, y1, x2, y2));
+	    break;
+	case 22:
+	    return (koch_calc(x1, y1, x2, y2));
+	    break;
+	case 23:
+	    return (hornflake_calc(x1, y1, x2, y2));
+	    break;
+	case 24:
+	    return (smand6_calc(x1, y1, x2, y2));
+	    break;
+	case 25:
+	    return (beryl_calc(x1, y1, x2, y2));
+	    break;
+        case 26:
+            return (goldsier_calc(x1, y1, x2, y2));
+            break;
+        case 27:
+            return (circle7_calc(x1, y1, x2, y2));
+            break;
+        case 28:
+            return (symbarn_calc(x1, y1, x2, y2));
+            break;
+	    
+#ifdef SFFE_USING
+	case 29:
+	    return (sffe_calc(x1, y1, x2, y2));
+	    break;
+#endif
+    } else
+	switch (cfractalc.currentformula - formulas) {	/* no periodicity checking and no smoothmode CALC */
+	case 0:
+	    return (mand_calc(x1, y1, x2, y2));
+	    break;
+	case 1:
+	    return (mand3_calc(x1, y1, x2, y2));
+	    break;
+	case 2:
+	    return (mand4_calc(x1, y1, x2, y2));
+	    break;
+	case 3:
+	    return (mand5_calc(x1, y1, x2, y2));
+	    break;
+	case 4:
+	    return (mand6_calc(x1, y1, x2, y2));
+	    break;
+	case 5:
+	    return (newton_calc(x1, y1, x2, y2));
+	    break;
+	case 6:
+	    return (newton4_calc(x1, y1, x2, y2));
+	    break;
+	case 7:
+	    return (barnsley1_calc(x1, y1, x2, y2));
+	    break;
+	case 8:
+	    return (barnsley2_calc(x1, y1, x2, y2));
+	    break;
+	case 9:
+	    return (barnsley3_calc(x1, y1, x2, y2));
+	    break;
+	case 10:
+	    return (octo_calc(x1, y1, x2, y2));
+	    break;
+	case 11:
+	    return (phoenix_calc(x1, y1, x2, y2));
+	    break;
+	case 12:
+	    return (magnet_calc(x1, y1, x2, y2));
+	    break;
+	case 13:
+	    return (magnet2_calc(x1, y1, x2, y2));
+	    break;
+	case 14:
+	    return (trice_calc(x1, y1, x2, y2));
+	    break;
+	case 15:
+	    return (catseye_calc(x1, y1, x2, y2));
+	    break;
+	case 16:
+	    return (mbar_calc(x1, y1, x2, y2));
+	    break;
+	case 17:
+	    return (mlambda_calc(x1, y1, x2, y2));
+	    break;
+	case 18:
+	    return (manowar_calc(x1, y1, x2, y2));
+	    break;
+	case 19:
+	    return (spider_calc(x1, y1, x2, y2));
+	    break;
+	case 20:
+	    return (sier_calc(x1, y1, x2, y2));
+	    break;
+	case 21:
+	    return (carpet_calc(x1, y1, x2, y2));
+	    break;
+	case 22:
+	    return (koch_calc(x1, y1, x2, y2));
+	    break;
+	case 23:
+	    return (hornflake_calc(x1, y1, x2, y2));
+	    break;
+	case 24:
+	    return (mand9_calc(x1, y1, x2, y2));
+	    break;
+	case 25:
+	    return (beryl_peri(x1, y1, x2, y2));
+	    break;
+        case 26:
+            return (goldsier_calc(x1, y1, x2, y2));
+	    break;
+        case 27:
+            return (circle7_calc(x1, y1, x2, y2));
+	    break;
+        case 28:
+            return (symbarn_calc(x1, y1, x2, y2));
+	    break;
+	    
+#ifdef SFFE_USING
+	case 29:
+	    return (sffe_calc(x1, y1, x2, y2));
+	    break;
+#endif
+	}
+    return 0;
+}
+#endif
+
+CONST struct formula *currentformula;
+CONST int nformulas = sizeof(formulas) / sizeof(struct formula);
+CONST int nmformulas = 16; // Is this correct here? -- Zoltan, 2009-07-30
diff --git a/src/engine/fractal.c b/src/engine/fractal.c
new file mode 100644
index 0000000..87da2c1
--- /dev/null
+++ b/src/engine/fractal.c
@@ -0,0 +1,471 @@
+/* 
+ *     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);
+}
diff --git a/src/engine/i386.c b/src/engine/i386.c
new file mode 100644
index 0000000..b7a862d
--- /dev/null
+++ b/src/engine/i386.c
@@ -0,0 +1,187 @@
+
+/*
+ * ctrl87.c
+ */
+
+
+#define __CONTROL87_C__
+
+
+#include "../include/i386/ctrl87.h"
+#include 
+
+#ifdef __GNUC__
+#ifdef __i386__
+#ifndef NOASSEMBLY
+
+/***** _control87 *****/
+unsigned short _control87(unsigned short newcw, unsigned short mask)
+{
+    unsigned short cw;
+
+    asm volatile ("                                                    \n\
+      wait                                                          \n\
+      fstcw  %0                                                       ": /* outputs */ "=m" (cw)
+		  :		/* inputs */
+	);
+
+    if (mask) {			/* mask is not 0 */
+	asm volatile ("                                                  \n\
+        mov    %2, %%ax                                             \n\
+        mov    %3, %%cx                                             \n\
+        and    %%cx, %%ax                                           \n\
+        not    %%cx                                                 \n\
+        nop                                                         \n\
+        wait                                                        \n\
+        mov    %1, %%dx                                             \n\
+        and    %%cx, %%dx                                           \n\
+        or     %%ax, %%dx                                           \n\
+        mov    %%dx, %0                                             \n\
+        wait                                                        \n\
+        fldcw  %1                                                     ":
+		      /* outputs */ "=m" (cw)
+		      : /* inputs */ "m"(cw), "m"(newcw), "m"(mask)
+		      : /* registers */ "ax", "cx", "dx"
+	    );
+    }
+    return cw;
+
+}				/* _control87 */
+#endif
+#endif
+#endif
+
+#ifdef __GNUC__
+#ifdef __i386__
+#if 0
+
+/*
+ * copy.c -- fast memcpy routines for Pentium using FPU
+ * Copyright (c) 1995, 1996 Robert Krawitz 
+ * and Gerhard Koerting (G.Koerting@techem.ruhr-uni-bochum.de)
+ * Exception handling in kernel/userspace routines by Gerhard
+ * Koerting.
+ * May be used and redistributed under the terms of the GNU Public License
+ */
+#include 
+
+#define CACHELINE 32
+#define CACHEMASK (CACHELINE - 1)
+#define BIGMASK (~255)
+#define SMALLMASK (~31)
+
+void *penium___zero_chunk(void *_to, size_t _bytes)
+{
+    unsigned long temp0, temp1;
+    register unsigned long to asm("di") = (unsigned long) _to;
+    register unsigned long bytes asm("dx") = (unsigned long) _bytes;
+    char save[42];
+    unsigned long zbuf[2] = { 0, 0 };
+    temp0 = to & 7;
+    if (temp0) {
+	bytes -= temp0;
+	asm __volatile__("cld\n\t"
+			 "rep; stosb\n\t":"=D"(to):"D"(to), "a"(0),
+			 "c"(temp0):"cx");
+    }
+    asm __volatile__("shrl $3, %0\n\t"
+		     "fstenv %4\n\t"
+		     "fstpt 32+%4\n\t"
+		     "movl (%1), %2\n\t"
+		     "fildq %3\n"
+		     "2:\n\t"
+		     "fstl (%1)\n\t"
+		     "addl $8, %1\n\t"
+		     "decl %0\n\t"
+		     "jne 2b\n\t"
+		     "fstpl %%st\n\t"
+		     "fldt 32+%4\n\t"
+		     "fldenv %4\n\t":"=&r"(temp0), "=&r"(to),
+		     "=&r"(temp1):"m"(*(char *) zbuf), "m"(*(char *) save),
+		     "0"(bytes), "1"(to));
+    bytes &= 7;
+    if (bytes) {
+	asm __volatile__("shrl $2, %%ecx\n\t"
+			 "cld\n\t"
+			 "rep ; stosl\n\t"
+			 "testb $2,%%dl\n\t"
+			 "je 111f\n\t"
+			 "stosw\n"
+			 "111:\ttestb $1,%%dl\n\t"
+			 "je 112f\n\t"
+			 "stosb\n"
+			 "112:":"=D"(to):"D"(to), "a"(0), "c"(bytes),
+			 "d"(bytes):"cx", "memory");
+    }
+    return _to;
+}
+
+void *pentium__memcpy_g(void *_to, const void *_from, size_t _bytes)
+{
+    register unsigned long from asm("si") = (unsigned long) _from;
+    register unsigned long to asm("di") = (unsigned long) _to;
+    register unsigned long bytes asm("dx") = (unsigned long) _bytes;
+    if (bytes >= 1024) {
+	unsigned long temp0, temp1;
+	char save[108];
+
+	temp0 = to & 7;
+	if (temp0) {
+	    bytes -= temp0;
+	    asm __volatile__("cld\n\t"
+			     "rep; movsb\n\t":"=D"(to), "=S"(from):"D"(to),
+			     "S"(from), "c"(temp0):"cx");
+	}
+	asm __volatile__("shrl $8, %0\n\t"
+			 "movl (%2), %3\n\t" "movl (%1), %3\n\t"
+			 /*"fsave %4\n" */
+			 "1:\n\t"
+			 "movl $4, %3\n"
+			 "2:\n\t"
+			 "fildq 0x0(%2)\n\t"
+			 "fildq 0x20(%2)\n\t"
+			 "fildq 0x40(%2)\n\t"
+			 "fildq 0x60(%2)\n\t"
+			 "fildq 0x80(%2)\n\t"
+			 "fildq 0xa0(%2)\n\t"
+			 "fildq 0xc0(%2)\n\t"
+			 "fildq 0xe0(%2)\n\t"
+			 "fxch\n\t"
+			 "fistpq 0xc0(%1)\n\t"
+			 "fistpq 0xe0(%1)\n\t"
+			 "fistpq 0xa0(%1)\n\t"
+			 "fistpq 0x80(%1)\n\t"
+			 "fistpq 0x60(%1)\n\t"
+			 "fistpq 0x40(%1)\n\t"
+			 "fistpq 0x20(%1)\n\t"
+			 "fistpq 0x0(%1)\n\t"
+			 "addl $8, %2\n\t"
+			 "addl $8, %1\n\t"
+			 "decl %3\n\t"
+			 "jne 2b\n\t"
+			 "addl $224, %2\n\t"
+			 "addl $224, %1\n\t" "decl %0\n\t" "jne 1b\n\t"
+			 /*"frstor %4\n\t" */
+			 :"=&r"(temp0), "=&r"(to), "=&r"(from),
+			 "=&r"(temp1):"m"(save[0]), "0"(bytes), "1"(to),
+			 "2"(from):"memory");
+	bytes &= 255;
+    }
+    if (bytes) {
+	asm __volatile__("shrl $2, %%ecx\n\t"
+			 "cld\n\t"
+			 "rep ; movsl\n\t"
+			 "testb $2,%%dl\n\t"
+			 "je 111f\n\t"
+			 "movsw\n"
+			 "111:\ttestb $1,%%dl\n\t"
+			 "je 112f\n\t"
+			 "movsb\n"
+			 "112:":"=D"(to), "=S"(from):"D"(to), "S"(from),
+			 "c"(bytes), "d"(bytes):"cx", "memory");
+    }
+    return _to;
+}
+#endif
+#endif
+#endif
diff --git a/src/engine/interlace.c b/src/engine/interlace.c
new file mode 100644
index 0000000..0971a5a
--- /dev/null
+++ b/src/engine/interlace.c
@@ -0,0 +1,134 @@
+#include 
+#ifndef _plan9_
+#ifdef NO_MALLOC_H
+#include 
+#else
+#include 
+#endif
+#include 		/*for NULL */
+#include 		/*for memcpy */
+#else
+#include 
+#include 
+#include 
+#endif
+#include 
+struct intdata {
+    unsigned char *lastent;
+    int changed;
+    int first;
+};
+static int requirement(struct filter *f, struct requirements *r)
+{
+    r->nimages = 1;
+    r->flags |= IMAGEDATA;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    int x;
+    struct intdata *d = (struct intdata *) f->data;
+    pixel_t **lines1 =
+	(pixel_t **) malloc(sizeof(*lines1) * i->image->height / 2),
+	**lines2 =
+	(pixel_t **) malloc(sizeof(*lines2) * i->image->height / 2);
+    if (lines1 == NULL)
+	return 0;
+    inhermisc(f, i);
+    d->first = 1;
+    if (lines2 == NULL) {
+	free(lines1);
+	return 0;
+    }
+    if (f->childimage != NULL)
+	destroy_image(f->childimage);
+    f->image = i->image;
+    f->image->flags |= PROTECTBUFFERS;
+    i->flags |= DATALOST;
+    for (x = 0; x < (i->image->height) / 2; x++) {
+	lines1[x] = i->image->currlines[x * 2];
+	lines2[x] = i->image->currlines[x * 2 + 1];
+    }
+    f->childimage = i->image =
+	create_image_lines(i->image->width, (i->image->height) / 2, 2,
+			   lines1, lines2, i->image->palette, NULL,
+			   FREELINES | PROTECTBUFFERS,
+			   f->image->pixelwidth,
+			   f->image->pixelheight * 2);
+    if (i->image == NULL) {
+	free(lines1);
+	free(lines2);
+	return 0;
+    }
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct intdata *i = (struct intdata *) calloc(1, sizeof(*i));
+    f->data = i;
+    f->name = "Interlace filter";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    free(f->data);
+    if (f->childimage != NULL)
+	destroy_image(f->childimage);
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    struct intdata *i = (struct intdata *) f->data;
+    int val;
+    if (!(f->req.flags & IMAGEDATA)
+	&& f->childimage->currlines[0] == i->lastent)
+	f->childimage->flip(f->childimage);
+    i->lastent = f->childimage->currlines[0];
+    val = f->previous->action->doit(f->previous, flags, time);
+    if (i->first) {
+	int y;
+	for (y = 0; y < f->childimage->height; y++)
+	    memcpy(f->childimage->oldlines[y], f->childimage->currlines[y],
+		   f->childimage->width * f->childimage->bytesperpixel);
+	i->first = 0;
+    }
+    if (val & CHANGED)
+	i->changed = 1, val |= ANIMATION;
+    else {
+	if (i->changed)
+	    val |= CHANGED;
+	i->changed = 0;
+    }
+    return (val);
+}
+
+static void convertup(struct filter *f, int *x, int *y)
+{
+    *y *= 2;
+    f->next->action->convertup(f->next, x, y);
+}
+
+static void convertdown(struct filter *f, int *x, int *y)
+{
+    *y /= 2;
+    f->previous->action->convertdown(f->previous, x, y);
+}
+
+CONST struct filteraction interlace_filter = {
+    "Interlace filter",
+    "interlace",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertup,
+    convertdown,
+    NULL
+};
diff --git a/src/engine/itersmall.c b/src/engine/itersmall.c
new file mode 100644
index 0000000..29985b4
--- /dev/null
+++ b/src/engine/itersmall.c
@@ -0,0 +1,171 @@
+#include 
+#ifndef _plan9_
+#ifndef NO_MALLOC_H
+#include 
+#endif
+#include 
+#ifdef HAVE_ALLOCA_H
+#include 
+#endif
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+#define SLARGEITER
+#include 
+#include 
+#define NCOLORS 256
+#define IMAGETYPE SMALLITER
+#define spixel_t pixel8_t
+struct siterdata {
+    struct palette *palette;
+};
+static int requirement(struct filter *f, struct requirements *r)
+{
+    f->req = *r;
+    r->nimages = 1;
+    r->flags &= ~IMAGEDATA;
+    r->supportedmask = MASK1BPP | MASK2BPP | MASK3BPP | MASK4BPP;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    struct siterdata *s = (struct siterdata *) f->data;
+    inhermisc(f, i);
+    if (!inherimage(f, i, TOUCHIMAGE, 0, 0, s->palette, 0, 0))
+	return 0;
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct siterdata *i = (struct siterdata *) calloc(1, sizeof(*i));
+    i->palette =
+	createpalette(0, 65536, IMAGETYPE, 0, 65536, NULL, NULL, NULL,
+		      NULL, NULL);
+    f->data = i;
+    f->name = "Smalliter image convertor";
+    return (f);
+}
+
+static void convert8(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    struct image *img1 = f->childimage, *img2 = f->image;
+    unsigned char *src, *srcend;
+    unsigned int *pixels = img2->palette->pixels;
+    pixel8_t *dest;
+    int i;
+    for (i = r1; i < r2; i++) {
+	src = img1->currlines[i];
+	dest = img2->currlines[i];
+	srcend = src + img1->width;
+	for (; src < srcend; src++, dest++)
+	    *dest = pixels[*src];
+    }
+}
+
+static void convert16(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    struct image *img1 = f->childimage, *img2 = f->image;
+    unsigned char *src, *srcend;
+    unsigned int *pixels = img2->palette->pixels;
+    pixel16_t *dest;
+    int i;
+    for (i = r1; i < r2; i++) {
+	src = img1->currlines[i];
+	dest = (pixel16_t *) img2->currlines[i];
+	srcend = src + img1->width;
+	for (; src < srcend; src++, dest++) {
+	    *dest = pixels[*src];
+	}
+    }
+}
+
+#ifdef STRUECOLOR24
+#include 
+static void convert24(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    struct image *img1 = f->childimage, *img2 = f->image;
+    unsigned char *src, *srcend;
+    unsigned int *pixels = img2->palette->pixels;
+    cpixel_t *dest;
+    int i;
+    for (i = r1; i < r2; i++) {
+	src = img1->currlines[i];
+	dest = (cpixel_t *) img2->currlines[i];
+	srcend = src + img1->width;
+	for (; src < srcend; src++, dest += 3)
+	    p_set(dest, pixels[*src]);
+    }
+}
+#endif
+static void convert32(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    struct image *img1 = f->childimage, *img2 = f->image;
+    unsigned char *src, *srcend;
+    unsigned int *pixels = img2->palette->pixels;
+    pixel32_t *dest;
+    int i;
+    for (i = r1; i < r2; i++) {
+	src = img1->currlines[i];
+	dest = (pixel32_t *) img2->currlines[i];
+	srcend = src + img1->width;
+	for (; src < srcend; src++, dest++)
+	    *dest = pixels[*src];
+    }
+}
+
+static void destroyinstance(struct filter *f)
+{
+    struct siterdata *i = (struct siterdata *) f->data;
+    destroypalette(i->palette);
+    free(f->data);
+    destroyinheredimage(f);
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    int val;
+    int size;
+    updateinheredimage(f);
+    if (f->image->palette->size < 256)
+	size = f->image->palette->size;
+    else
+	size = 256;
+    if (size != f->childimage->palette->size)
+	f->childimage->palette->size =
+	    size, f->childimage->palette->version++;
+    val = f->previous->action->doit(f->previous, flags, time);
+    if (f->image->palette->type != SMALLITER
+	|| f->image->currlines[0] != f->childimage->currlines[0]) {
+    drivercall(*f->image,
+		   xth_function(convert8, f, f->image->height),
+		   xth_function(convert16, f, f->image->height),
+		   xth_function(convert24, f, f->image->height),
+		   xth_function(convert32, f, f->image->height))}
+    xth_sync();
+    return val;
+}
+
+CONST struct filteraction smalliter_filter = {
+    "Smalliter image convertor",
+    "smalliter",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdowngeneric,
+    NULL
+};
diff --git a/src/engine/julia.c b/src/engine/julia.c
new file mode 100644
index 0000000..d471bc8
--- /dev/null
+++ b/src/engine/julia.c
@@ -0,0 +1,120 @@
+#ifdef _plan9_
+#include 
+#include 
+#include 
+#else
+#include 
+#include 
+#include 
+#ifndef NO_MALLOC_H
+#include 
+#endif
+#include 
+#include 
+#endif
+#include 
+#include "julia.h"
+#include 
+#ifdef HAVE_ALLOCA_H
+#include 
+#endif
+#include 
+#include 
+
+
+/*most of code was moved to docalc.c */
+
+#ifdef STATISTICS
+int iters2, guessed2, unguessed2, total2;
+#endif
+void
+init_julia(struct image *img, number_t rangep, number_t range,
+	   number_t xdelta, number_t ystep)
+{
+    int i, j, x, y;
+    register number_t im;
+    unsigned char *addr, **addr1 = img->currlines;
+    for (i = 0; i < img->height; i++) {
+	im = IMIN + (i + 0.5) * ystep;
+	x = (int) (sqrt(rangep - im * im) * xdelta + 0.5);
+	if (!i || i == img->height - 1)
+	    x = 0;
+	addr = addr1[i];
+	y = img->width / 2 - x;
+	if (y < 1)
+	    y = 1;
+	for (j = 0; j < y; j++) {
+	    addr[j] = 1;
+	}
+	y = img->width;
+	j = img->width / 2 + x;
+	if (j >= img->width)
+	    j = img->width - 1;
+	for (j = img->width / 2 + x; j < y; j++) {
+	    addr[j] = 1;
+	}
+    }
+    for (i = 0; i < img->height; i++) {
+	addr = addr1[i];
+	memset_long((char *) addr, NOT_CALCULATED, img->width);
+    }
+}
+
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    r->nimages = 1;
+    r->flags = 0;
+    r->supportedmask = SMALLITER;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    inhermisc(f, i);
+    f->image = i->image;
+    return (1);
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    f->name = "Julia generator";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    /*if(f->image->nimages==2) f->image->flip(f->image); */
+    if (f->fractalc->currentformula->calculate_julia != NULL) {
+	f->fractalc->currentformula->calculate_julia(f->image,
+						     f->fractalc->pre,
+						     f->fractalc->pim);
+	return (CHANGED);
+    }
+#ifdef STATISTICS
+    printf("Total guessed %i, unguessed %i, iterations %i\n", guessed2,
+	   unguessed2, iters2);
+#endif
+
+    return 0;
+}
+
+CONST struct filteraction julia_filter = {
+    "Julia generator",
+    "julia",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdowngeneric,
+    NULL,
+};
diff --git a/src/engine/julia.h b/src/engine/julia.h
new file mode 100644
index 0000000..a9377e7
--- /dev/null
+++ b/src/engine/julia.h
@@ -0,0 +1,18 @@
+#ifndef JULIA_H
+#define JULIA_H
+void init_julia(struct image *img, number_t rangep, number_t range,
+		number_t xdelta, number_t ystep);
+#define SAG			/*solid anti-guessing */
+#define NOT_CALCULATED (unsigned char)0
+#define INSET (unsigned char)0
+#define INPROCESS (unsigned char)255
+#define RMIN -range
+#define RMAX range
+#define IMIN -range
+#define IMAX range
+#define QMAX 1000
+#ifdef STATISTICS
+extern int iters2, guessed2, unguessed2, total2, frames2;
+#endif
+
+#endif
diff --git a/src/engine/paletted.c b/src/engine/paletted.c
new file mode 100644
index 0000000..2a1a3f0
--- /dev/null
+++ b/src/engine/paletted.c
@@ -0,0 +1,22 @@
+#ifndef UNSUPPORTED
+static void cpalette(void *data, struct taskinfo *task, int r1, int r2)
+{
+    pixel8_t *src, *srcend;
+    cppixel_t dest;
+    struct filter *f = (struct filter *) data;
+    struct palettedata *s = (struct palettedata *) f->data;
+    int i;
+    unsigned int *table = s->table;
+    for (i = r1; i < r2; i++) {
+	src = f->childimage->currlines[i];
+	srcend = src + f->image->width;
+	dest = (cppixel_t) f->image->currlines[i];
+	while (src < srcend) {
+	    p_set(dest, table[*src]);
+	    src++;
+	    p_inc(dest, 1);
+	}
+    }
+}
+#endif
+#undef cpalette
diff --git a/src/engine/palettef.c b/src/engine/palettef.c
new file mode 100644
index 0000000..3bdcbb0
--- /dev/null
+++ b/src/engine/palettef.c
@@ -0,0 +1,165 @@
+#include 
+#ifndef _plan9_
+#ifdef NO_MALLOC_H
+#include 
+#else
+#include 
+#endif
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+#include 
+#include 
+#include 
+struct palettedata {
+    struct palette *palette;
+    int active;
+    unsigned int table[256];
+};
+#include 
+#define cpalette palette8
+#include "paletted.c"
+
+#include 
+#define cpalette palette32
+#include "paletted.c"
+
+#include 
+#define cpalette palette24
+#include "paletted.c"
+
+#include 
+#define cpalette palette16
+#include "paletted.c"
+
+static void mysetcolor(struct palette *p, int start, int end, rgb_t * rgb)
+{
+    p->data = &p;
+}
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    f->req = *r;
+    r->nimages = 1;
+    r->flags &= ~(IMAGEDATA);
+    r->supportedmask = MASK1BPP | MASK2BPP | MASK3BPP | MASK4BPP;
+
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    struct palettedata *s = (struct palettedata *) f->data;
+    inhermisc(f, i);
+    if (i->image->palette->type != C256
+	|| i->image->palette->setpalette == NULL) {
+	if (datalost(f, i) || i->image->version != f->imageversion
+	    || !s->active) {
+	    if (!s->active) {
+		struct palette *palette;
+		palette = clonepalette(i->image->palette);
+		restorepalette(s->palette, palette);
+		destroypalette(palette);
+	    }
+	    s->palette->data = s;
+	    if (i->image->palette->maxentries < 256)
+		s->palette->maxentries = i->image->palette->maxentries;
+	    else
+		s->palette->maxentries = 256;
+	    s->active = 1;
+	}
+	if (!inherimage
+	    (f, i, TOUCHIMAGE | IMAGEDATA, 0, 0, s->palette, 0, 0))
+	    return 0;
+	setfractalpalette(f, s->palette);
+	f->queue->saveimage = f->childimage;
+	f->queue->palettechg = f;
+    } else {
+	if (s->active) {
+	    f->image = i->image;
+	    restorepalette(f->image->palette, s->palette);
+	}
+	s->active = 0;
+    }
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct palettedata *i = (struct palettedata *) calloc(1, sizeof(*i));
+    i->active = 0;
+    i->palette =
+	createpalette(0, 256, C256, 0, 256, NULL, mysetcolor, NULL, NULL,
+		      NULL);
+    f->childimage = NULL;
+    f->data = i;
+    f->name = "Palette emulator";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    struct palettedata *i = (struct palettedata *) f->data;
+    destroypalette(i->palette);
+    destroyinheredimage(f);
+    free(f->data);
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time1)
+{
+    int val;
+    int time = time1;
+    struct palettedata *s = (struct palettedata *) f->data;
+    if (s->active)
+	updateinheredimage(f);
+    if (flags & PALETTEONLY)
+	val = 0;
+    else
+	val = f->previous->action->doit(f->previous, flags, time);
+    if (s->active) {
+	int i;
+	if (s->palette->data != NULL) {
+	    val |= CHANGED;
+	    restorepalette(f->image->palette, f->childimage->palette);
+	    for (i = 0; i < 256; i++) {
+		s->table[i] =
+		    f->image->palette->pixels[i % f->image->palette->size];
+	    }
+	    s->palette->data = NULL;
+	}
+	drivercall(*f->image,
+		   xth_function(palette8, f, f->image->height),
+		   xth_function(palette16, f, f->image->height),
+		   xth_function(palette24, f, f->image->height),
+		   xth_function(palette32, f, f->image->height));
+	xth_sync();
+    }
+    return val;
+}
+
+static void myremovefilter(struct filter *f)
+{
+    struct palettedata *s = (struct palettedata *) f->data;
+    if (s->active) {
+	restorepalette(f->image->palette, s->palette);
+    }
+}
+
+CONST struct filteraction palette_filter = {
+    "Palette emulator",
+    "palette",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdowngeneric,
+    myremovefilter
+};
diff --git a/src/engine/plane.c b/src/engine/plane.c
new file mode 100644
index 0000000..20e08e7
--- /dev/null
+++ b/src/engine/plane.c
@@ -0,0 +1,144 @@
+/* 
+ *     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.
+ */
+#ifdef __EMX__
+#include 
+#include 
+#endif
+#ifdef _plan9_
+#include 
+#include 
+#ifndef NULL
+#define NULL (void *)0
+#endif
+#else
+#include 
+#include 
+#include 
+#ifdef HAVE_LIMITS_H
+#include 
+#endif
+#include 
+#endif
+#include 
+#include 
+#include 
+CONST char *CONST planename[] = {
+    "mu",
+    "1/mu",
+    "1/(mu+0.25)",
+    "lambda",
+    "1/lambda",
+    "1/(lambda-1)",
+    "1/(mu-1.40115)",
+    NULL
+};
+
+
+REGISTERS(3)
+void recalculate(int plane, number_t * x1, number_t * y1)
+{
+    number_t x = *x1, y = *y1;
+    switch (plane) {
+    case 1:
+	{			/* 1/mu */
+	    number_t t;
+	    if (myabs(x) + myabs(y) < 0.000001)
+		t = INT_MAX, y = INT_MAX;
+	    else {
+
+		c_div(1, 0, x, y, t, y);
+	    }
+	    x = t;
+	}
+	break;
+    case 2:
+	{			/* 1/(mu + 0.25) */
+	    number_t t;
+	    if (myabs(x) + myabs(y) < 0.000001)
+		t = INT_MAX, y = INT_MAX;
+	    else {
+
+		c_div(1, 0, x, y, t, y);
+	    }
+	    x = t;
+	    x += 0.25;
+	}
+	break;
+    case 3:			/* lambda */
+	{
+	    number_t tr, ti, mr, mi;
+
+	    mr = x, mi = y;
+	    c_pow2(x, y, tr, ti);
+	    c_div(tr, ti, 4, 0, x, y);
+	    c_div(mr, mi, 2, 0, tr, ti);
+	    c_sub(tr, ti, x, y, mr, mi);
+	    x = mr, y = mi;
+	}
+	break;
+    case 4:			/* 1/lambda */
+	{
+	    number_t tr, ti, mr, mi;
+
+	    c_div(1, 0, x, y, tr, y);
+	    x = tr;
+	    mr = x, mi = y;
+	    c_pow2(x, y, tr, ti);
+	    c_div(tr, ti, 4, 0, x, y);
+	    c_div(mr, mi, 2, 0, tr, ti);
+	    c_sub(tr, ti, x, y, mr, mi);
+	    x = mr, y = mi;
+	}
+	break;
+    case 5:			/* 1/(lambda-1) */
+	{
+	    number_t tr, ti, mr, mi;
+
+	    c_div(1, 0, x, y, tr, y);
+	    x = tr + 1;
+	    mr = x, mi = y;
+	    c_pow2(x, y, tr, ti);
+	    c_div(tr, ti, 4, 0, x, y);
+	    c_div(mr, mi, 2, 0, tr, ti);
+	    c_sub(tr, ti, x, y, mr, mi);
+	    x = mr, y = mi;
+	}
+	break;
+    case 6:
+	{			/* 1/(mu + 0.25) */
+	    number_t t;
+	    if (myabs(x) + myabs(y) < 0.000001)
+		t = INT_MAX, y = INT_MAX;
+	    else {
+
+		c_div(1, 0, x, y, t, y);
+	    }
+	    x = t;
+	    x -= 1.40115;
+	}
+	break;
+    default:
+	break;
+    }
+    *x1 = x;
+    *y1 = y;
+}
diff --git a/src/engine/rotate.c b/src/engine/rotate.c
new file mode 100644
index 0000000..092501d
--- /dev/null
+++ b/src/engine/rotate.c
@@ -0,0 +1,200 @@
+/* An rotation filter. Uses bressemham algorithm combined with dda to rotate
+ * image around center
+ * This filter is used internally by XaoS and is unvisible to normal user in
+ * 'E' menu.
+ * It is used to implement fast rotation mode
+ */
+#include 
+#ifndef _plan9_
+#include 
+#include 
+#include 
+#ifndef __cplusplus
+#include 
+#endif
+#ifdef NO_MALLOC_H
+#include 
+#else
+#include 
+#endif
+#else
+#include 
+#include 
+#include 
+#endif
+#define SLARGEITER
+#include 
+#include 
+
+struct rotatedata {
+    number_t angle;
+    number_t x1, y1, x2, y2, xx1, yy1, xx2, yy2;
+};
+
+#include 
+#define do_rotate do_rotate8
+#include "rotated.c"
+
+#include 
+#define do_rotate do_rotate32
+#include "rotated.c"
+
+#include 
+#define do_rotate do_rotate24
+#include "rotated.c"
+
+#include 
+#define do_rotate do_rotate16
+#include "rotated.c"
+
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    f->req = *r;
+    r->nimages = 1;
+    r->flags &= ~IMAGEDATA;
+    r->supportedmask = MASK1BPP | MASK2BPP | MASK3BPP | MASK4BPP;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    float size, pixelsize;
+    struct rotatedata *s = (struct rotatedata *) f->data;
+    inhermisc(f, i);
+    s->angle = INT_MAX;
+    /*in/out coloring modes looks better in iter modes. This also saves some
+       memory in truecolor. */
+    if (i->image->pixelwidth < i->image->pixelheight)
+	pixelsize = i->image->pixelwidth;
+    else
+	pixelsize = i->image->pixelheight;
+    size =
+	sqrt(i->image->width * i->image->width * i->image->pixelwidth *
+	     i->image->pixelwidth +
+	     i->image->height * i->image->height * i->image->pixelheight *
+	     i->image->pixelheight);
+    if (!inherimage
+	(f, i, TOUCHIMAGE | NEWIMAGE, (int) (size / pixelsize + 1),
+	 (int) (size / pixelsize + 1), NULL, pixelsize, pixelsize))
+	return 0;
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct rotatedata *i = (struct rotatedata *) calloc(1, sizeof(*i));
+    f->name = "Rotation filter";
+    f->data = i;
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    free(f->data);
+    destroyinheredimage(f);
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    int val;
+    struct rotatedata *s = (struct rotatedata *) f->data;
+    number_t angle = f->fractalc->angle;
+    number_t wx = f->fractalc->windowwidth, wy = f->fractalc->windowheight;
+    number_t rr = f->fractalc->s.rr, ir = f->fractalc->s.ri;
+    f->fractalc->windowwidth = f->fractalc->windowheight =
+	f->childimage->width * f->childimage->pixelwidth;
+    f->fractalc->s.rr *= f->fractalc->windowwidth / wx;
+    f->fractalc->s.ri *= f->fractalc->windowheight / wy;
+    f->fractalc->windowwidth = f->fractalc->windowheight = 1;
+    f->fractalc->angle = 0;
+    update_view(f->fractalc);	/*update rotation tables */
+    updateinheredimage(f);
+    val = f->previous->action->doit(f->previous, flags, time);
+    f->fractalc->angle = angle;
+    update_view(f->fractalc);	/*update rotation tables */
+    f->fractalc->s.rr = rr;
+    f->fractalc->s.ri = ir;
+    f->fractalc->windowwidth = wx;
+    f->fractalc->windowheight = wy;
+    if ((val & CHANGED) || s->angle != angle) {
+	s->xx2 = f->image->width * f->image->pixelwidth / 2;
+	s->yy2 = f->image->height * f->image->pixelheight / 2;
+	s->x1 = -s->xx2;
+	s->y1 = -s->yy2;
+	s->x2 = -s->xx2;
+	s->y2 = s->yy2;
+	s->xx1 = s->xx2;
+	s->yy1 = -s->yy2;
+	rotateback(*f->fractalc, s->x1, s->y1);
+	rotateback(*f->fractalc, s->x2, s->y2);
+	rotateback(*f->fractalc, s->xx1, s->yy1);
+	rotateback(*f->fractalc, s->xx2, s->yy2);
+	s->x1 /= f->childimage->pixelwidth;
+	s->x1 += f->childimage->width / 2;
+	s->y1 /= f->childimage->pixelwidth;
+	s->y1 += f->childimage->width / 2;
+	s->xx1 /= f->childimage->pixelwidth;
+	s->xx1 += f->childimage->width / 2;
+	s->yy1 /= f->childimage->pixelwidth;
+	s->yy1 += f->childimage->width / 2;
+	s->x2 /= f->childimage->pixelwidth;
+	s->x2 += f->childimage->width / 2;
+	s->y2 /= f->childimage->pixelwidth;
+	s->y2 += f->childimage->width / 2;
+	s->xx2 /= f->childimage->pixelwidth;
+	s->xx2 += f->childimage->width / 2;
+	s->yy2 /= f->childimage->pixelwidth;
+	s->yy2 += f->childimage->width / 2;
+
+	drivercall(*f->image,
+		   xth_function(do_rotate8, f, f->image->height),
+		   xth_function(do_rotate16, f, f->image->height),
+		   xth_function(do_rotate24, f, f->image->height),
+		   xth_function(do_rotate32, f, f->image->height));
+	xth_sync();
+	val |= CHANGED;
+    }
+    return val;
+}
+
+static void convertup(struct filter *f, int *x, int *y)
+{
+    number_t xd =
+	(*x - f->childimage->width / 2) * f->childimage->pixelwidth;
+    number_t yd =
+	(*y - f->childimage->height / 2) * f->childimage->pixelheight;
+    *x = (int) (f->image->width / 2 + xd / f->image->pixelwidth);
+    *y = (int) (f->image->height / 2 + yd / f->image->pixelheight);
+    if (f->next != NULL)
+	f->next->action->convertup(f->next, x, y);
+}
+
+static void convertdown(struct filter *f, int *x, int *y)
+{
+    number_t xd = (*x - f->image->width / 2) * f->image->pixelwidth;
+    number_t yd = (*y - f->image->height / 2) * f->image->pixelheight;
+    *x = (int) (f->childimage->width / 2 + xd / f->childimage->pixelwidth);
+    *y = (int) (f->childimage->height / 2 +
+		yd / f->childimage->pixelheight);
+    if (f->previous != NULL)
+	f->previous->action->convertdown(f->previous, x, y);
+}
+
+
+
+CONST struct filteraction rotate_filter = {
+    "Image rotation",
+    "rotate",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertup,
+    convertdown,
+    NULL
+};
diff --git a/src/engine/rotated.c b/src/engine/rotated.c
new file mode 100644
index 0000000..69e24fd
--- /dev/null
+++ b/src/engine/rotated.c
@@ -0,0 +1,56 @@
+#ifndef UNSUPPORTED
+static void do_rotate(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    struct rotatedata *s = (struct rotatedata *) f->data;
+    double xstep = (s->x2 - s->x1) * 65536 / f->image->height;
+    double ystep = (s->y2 - s->y1) * 65536 / f->image->height;
+    double x = (s->x1) * 65536, y = (s->y1) * 65536;
+
+    int ixstep = (int) ((s->xx1 - s->x1) * 65536);
+    int iystep = (int) ((s->yy1 - s->y1) * 65536);
+    int i;
+
+    if (x < 0)
+	x = 0;			/*avoid shifting problems */
+    if (y < 0)
+	y = 0;
+
+    ixstep /= f->image->width;
+    iystep /= f->image->width;
+
+    /* I do floating point dda here since I expect that registers used by dda will 
+     * not conflict with registers of integer one used by main loop so it will be 
+     * faster than dda from stack :)
+     */
+    x += r1 * xstep;
+    y += r1 * ystep;
+    for (i = r1; i < r2; i++) {
+
+	{
+	    register int ix = (int) x;
+	    register int iy = (int) y;
+	    register cpixel_t **vbuff =
+		(cpixel_t **) f->childimage->currlines;
+	    register cpixel_t *end =
+		p_add((cpixel_t *) f->image->currlines[i],
+		      f->image->width), *dest =
+		(cpixel_t *) f->image->currlines[i];
+	    register int iixstep = ixstep, iiystep = iystep;
+
+	    while (dest < end) {
+		p_copy(dest, 0, (cpixel_t *) (vbuff[iy >> 16]),
+		       (ix >> 16));
+		p_inc(dest, 1);
+		ix += iixstep;
+		iy += iiystep;
+	    }
+	}
+
+	x += xstep;
+	y += ystep;
+
+    }
+}
+#endif
+#undef do_rotate
diff --git a/src/engine/star.c b/src/engine/star.c
new file mode 100644
index 0000000..179894e
--- /dev/null
+++ b/src/engine/star.c
@@ -0,0 +1,135 @@
+#include 
+#ifndef _plan9_
+#ifndef NO_MALLOC_H
+#include 
+#endif
+#include 
+#include 
+#ifdef HAVE_ALLOCA_H
+#include 
+#endif
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+#include 
+#include 
+
+struct starfielddata {
+    struct palette *palette;
+    struct palette *savedpalette;
+};
+
+static unsigned int state;
+static INLINE void mysrandom(unsigned int x)
+{
+    state = x;
+}
+
+#define MYLONG_MAX 0xffffff	/*this is enought for me. */
+static INLINE unsigned int myrandom(void)
+{
+    state = ((state * 1103515245) + 12345) & MYLONG_MAX;
+    return state;
+}
+
+#define IMAGETYPE SMALLITER
+#include 
+#define do_starfield do_starfield8
+#include "stard.c"
+#include 
+#define do_starfield do_starfield16
+#include "stard.c"
+#include 
+#define do_starfield do_starfield24
+#include "stard.c"
+#include 
+#define do_starfield do_starfield32
+#include "stard.c"
+static int requirement(struct filter *f, struct requirements *r)
+{
+    f->req = *r;
+    r->nimages = 1;
+    r->flags &= ~IMAGEDATA;
+    r->supportedmask =
+	C256 | TRUECOLOR24 | TRUECOLOR | TRUECOLOR16 | GRAYSCALE;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    struct starfielddata *s = (struct starfielddata *) f->data;
+    inhermisc(f, i);
+    if (s->savedpalette == NULL)
+	s->savedpalette = clonepalette(i->image->palette);
+    mkstarfieldpalette(i->image->palette);
+    if (!inherimage(f, i, TOUCHIMAGE, 0, 0, s->palette, 0, 0)) {
+	return 0;
+    }
+    setfractalpalette(f, s->savedpalette);
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct starfielddata *i =
+	(struct starfielddata *) calloc(1, sizeof(*i));
+    i->savedpalette = NULL;
+    i->palette =
+	createpalette(0, 65536, IMAGETYPE, 0, 65536, NULL, NULL, NULL,
+		      NULL, NULL);
+    f->data = i;
+    f->name = "Starfield";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    struct starfielddata *i = (struct starfielddata *) f->data;
+    if (i->savedpalette != NULL)
+	destroypalette(i->savedpalette);
+    destroypalette(i->palette);
+    destroyinheredimage(f);
+    free(f);
+    free(i);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    int val;
+    val = f->previous->action->doit(f->previous, flags, time);
+    drivercall(*f->image,
+	       xth_function(do_starfield8, f, f->image->height),
+	       xth_function(do_starfield16, f, f->image->height),
+	       xth_function(do_starfield24, f, f->image->height),
+	       xth_function(do_starfield32, f, f->image->height));
+    xth_sync();
+    return val | CHANGED;
+}
+
+static void myremovefilter(struct filter *f)
+{
+    struct starfielddata *s = (struct starfielddata *) f->data;
+    if (s->savedpalette != NULL) {
+	restorepalette(f->image->palette, s->savedpalette);
+	destroypalette(s->savedpalette);
+	s->savedpalette = NULL;
+    }
+}
+
+CONST struct filteraction starfield_filter = {
+    "Starfield",
+    "starfield",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdowngeneric,
+    myremovefilter
+};
diff --git a/src/engine/stard.c b/src/engine/stard.c
new file mode 100644
index 0000000..e6e58bc
--- /dev/null
+++ b/src/engine/stard.c
@@ -0,0 +1,31 @@
+#ifndef UNSUPPORTED
+static void do_starfield(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    cpixel_t *dest;
+    pixel8_t *src, *srcend;
+    unsigned int color;
+    int y;
+    cpixeldata_t black = (cpixeldata_t) f->image->palette->pixels[0];
+    mysrandom((unsigned int) rand());
+    for (y = r1; y < r2; y++) {
+	src = f->childimage->currlines[y];
+	srcend = f->childimage->currlines[y] + f->childimage->width;
+	dest = (cpixel_t *) f->image->currlines[y];
+	while (src < srcend) {
+	    color = ((unsigned int) myrandom() >> 7) & 15;
+	    if (!*src
+		|| (unsigned int) *src * (unsigned int) *src *
+		(unsigned int) *src >
+		(unsigned int) ((unsigned int) myrandom() & (0xffffff))) {
+		p_set(dest,
+		      (cpixeldata_t) f->image->palette->pixels[color]);
+	    } else
+		p_set(dest, black);
+	    p_inc(dest, 1);
+	    src++;
+	}
+    }
+}
+#endif
+#undef do_starfield
diff --git a/src/engine/stereod.c b/src/engine/stereod.c
new file mode 100644
index 0000000..26ac857
--- /dev/null
+++ b/src/engine/stereod.c
@@ -0,0 +1,51 @@
+#ifndef UNSUPPORTED
+static void
+do_stereogram(void *data, struct taskinfo *task, int r1, int r2)
+{
+    struct filter *f = (struct filter *) data;
+    int i, y, lc;
+    struct stereogramdata *s = (struct stereogramdata *) f->data;
+    register cpixel_t *cs, *c, *src, *src1, *ce;
+    register spixel_t *c1;
+    unsigned int *pixels = f->image->palette->pixels;
+    s->minc = NCOLORS;
+    for (i = r1; i < r2; i++) {
+	int i1;
+	for (i1 = 0; i1 < 2; i1++) {
+	    c1 = (spixel_t *) f->childimage->currlines[i];
+	    c = cs = (cpixel_t *) f->image->currlines[2 * i + i1];
+	    ce = p_add(cs, f->image->width);
+	    src = src1 = c;
+	    lc = 1024;
+	    while (c < ce) {
+		y = *c1;
+		if (y == lc)
+		    p_inc(src, 2);
+		else {
+		    lc = y;
+		    if (y < s->minc && y != 0)
+			s->minc = y;
+		    y = table[y];
+		    src = p_add(c, -y);
+		}
+		if (src < src1) {
+		    p_set(c, pixels[(rand() & 15)]);
+		    p_setp(c, 1, pixels[(rand() & 15)]);
+		} else {
+		    if (src <= cs) {
+			p_set(c, pixels[(rand() & 15)]);
+			p_setp(c, 1, pixels[(rand() & 15)]);
+		    } else {
+			p_copy(c, 0, src, 0);
+			p_copy(c, 1, src, 1);
+		    }
+		    src1 = src;
+		}
+		p_inc(c, 2);
+		c1++;
+	    }
+	}
+    }
+}
+#endif
+#undef do_stereogram
diff --git a/src/engine/stereogram.c b/src/engine/stereogram.c
new file mode 100644
index 0000000..28f0c01
--- /dev/null
+++ b/src/engine/stereogram.c
@@ -0,0 +1,193 @@
+#ifndef _plan9_
+#include 
+#ifndef NO_MALLOC_H
+#include 
+#endif
+#ifdef HAVE_ALLOCA_H
+#include 
+#endif
+#include 
+#else
+#include 
+#include 
+#include 
+#endif
+#include 
+#include 
+
+#define PIXELWIDTH (f->image->pixelwidth)	/*all distances in cm */
+#define PIXELHEIGHT (f->image->pixelheight)
+
+#define USER_DIST  (60.0)
+#define INDEX_DIST (0.3)
+#define EYE_DIST   (8.5)
+#define START1 (60.0)
+#define FNC(x) x
+
+#define NCOLORS 256
+#define IMAGETYPE SMALLITER
+#define spixel_t pixel8_t
+static int *table;
+struct stereogramdata {
+    int minc;
+    struct palette *palette;
+    struct palette *savedpalette;
+};
+
+#include 
+#define do_stereogram do_stereogram8
+#include "stereod.c"
+
+#include 
+#define do_stereogram do_stereogram16
+#include "stereod.c"
+
+#include 
+#define do_stereogram do_stereogram24
+#include "stereod.c"
+
+#include 
+#define do_stereogram do_stereogram32
+#include "stereod.c"
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    f->req = *r;
+    r->nimages = 1;
+    r->flags &= ~IMAGEDATA;
+    r->supportedmask =
+	C256 | TRUECOLOR | TRUECOLOR24 | TRUECOLOR16 | GRAYSCALE;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    struct stereogramdata *s = (struct stereogramdata *) f->data;
+    inhermisc(f, i);
+    if (s->savedpalette == NULL)
+	s->savedpalette = clonepalette(i->image->palette);
+    mkstereogrampalette(i->image->palette);
+    if (!inherimage
+	(f, i, TOUCHIMAGE, i->image->width / 2, (i->image->height) / 2,
+	 s->palette, i->image->pixelwidth * 2, i->image->pixelheight * 2))
+	return 0;
+    setfractalpalette(f, s->savedpalette);
+    return (f->previous->action->initialize(f->previous, i));
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct stereogramdata *i =
+	(struct stereogramdata *) calloc(1, sizeof(*i));
+    i->minc = 0;
+    i->savedpalette = NULL;
+    i->palette =
+	createpalette(0, 65536, IMAGETYPE, 0, 65536, NULL, NULL, NULL,
+		      NULL, NULL);
+    f->data = i;
+    f->name = "Random dot stereogram";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    struct stereogramdata *i = (struct stereogramdata *) f->data;
+    if (i->savedpalette != NULL)
+	destroypalette(i->savedpalette);
+    destroypalette(i->palette);
+    destroyinheredimage(f);
+    free(f);
+    free(i);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    int val;
+    struct stereogramdata *s = (struct stereogramdata *) f->data;
+    int i, y;
+    double start, maxdist, dist;
+    updateinheredimage(f);
+    if (f->fractalc->maxiter < NCOLORS)
+	s->palette->size = f->fractalc->maxiter;
+    else
+	s->palette->size = NCOLORS;
+    val = f->previous->action->doit(f->previous, flags, time);
+#ifdef HAVE_ALLOCA
+    table = (int *) alloca(sizeof(int) * NCOLORS);
+#else
+    table = (int *) malloc(sizeof(int) * NCOLORS);
+#endif
+    dist = (f->fractalc->s.rr) / 2;
+    maxdist = INDEX_DIST * FNC(f->fractalc->maxiter) + START1;
+    do {
+	start = dist * maxdist - INDEX_DIST * FNC(s->minc);
+	maxdist *= 5;
+    }
+    while (start + INDEX_DIST * (FNC(s->minc)) < 25.0);
+    if (f->fractalc->maxiter < NCOLORS)
+	y = f->fractalc->maxiter;
+    else
+	y = NCOLORS;
+    if (y < 256)
+	y = 256;
+    for (i = 0; i < y; i++) {
+	double dist;
+	if (i != 0)
+	    dist = i;
+	else
+	    dist = y - 1;
+	dist = INDEX_DIST * (FNC(dist)) + start;
+	table[i] =
+	    (int) (EYE_DIST * dist / (dist + USER_DIST) / PIXELWIDTH);
+    }
+    drivercall(*f->image,
+	       xth_function(do_stereogram8, f, f->childimage->height),
+	       xth_function(do_stereogram16, f, f->childimage->height),
+	       xth_function(do_stereogram24, f, f->childimage->height),
+	       xth_function(do_stereogram32, f, f->childimage->height));
+    xth_sync();
+#ifndef HAVE_ALLOCA
+    free(table);
+#endif
+    return val;
+}
+
+static void convertup(struct filter *f, int *x, int *y)
+{
+    *y *= 2;
+    *x *= 2;
+    f->next->action->convertup(f->next, x, y);
+}
+
+static void convertdown(struct filter *f, int *x, int *y)
+{
+    *y /= 2;
+    *x /= 2;
+    if (f->previous != NULL)
+	f->previous->action->convertdown(f->previous, x, y);
+}
+
+static void myremovefilter(struct filter *f)
+{
+    struct stereogramdata *s = (struct stereogramdata *) f->data;
+    if (s->savedpalette != NULL) {
+	restorepalette(f->image->palette, s->savedpalette);
+	destroypalette(s->savedpalette);
+	s->savedpalette = NULL;
+    }
+}
+
+CONST struct filteraction stereogram_filter = {
+    "Random dot stereogram",
+    "stereogram",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertup,
+    convertdown,
+    myremovefilter
+};
diff --git a/src/engine/subwindow.c b/src/engine/subwindow.c
new file mode 100644
index 0000000..19b78bf
--- /dev/null
+++ b/src/engine/subwindow.c
@@ -0,0 +1,236 @@
+#ifndef _plan9_
+#include 
+#ifdef NO_MALLOC_H
+#include 
+#else
+#include 
+#endif
+#include 		/*for NULL */
+#include 		/*for memcpy */
+#else
+#include 
+#include 
+#include 
+#endif
+#include 
+#include 
+struct subdata {
+    struct filter *second;
+    struct image *image;
+    pixel_t **currlines;
+    int recal;
+    int forpversion, forversion;
+    number_t pre, pim;
+};
+void subwindow_setsecond(struct filter *f, struct filter *f1)
+{
+    struct subdata *s = (struct subdata *) f->data;
+    s->second = f1;
+}
+
+static void myflip(struct image *image)
+{
+    struct subdata *s = (struct subdata *) image->data;
+    flipgeneric(image);
+    s->image->flip(s->image);
+    s->currlines = s->image->currlines;
+}
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    r->nimages = 2;
+    r->flags |= IMAGEDATA;
+    return (f->next->action->requirement(f->next, r));
+}
+
+extern CONST struct filteraction threed_filter;
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+    struct subdata *s = (struct subdata *) f->data;
+    int x;
+    int val = 0;
+    pixel_t **lines1, **lines2 = NULL;
+    double size;
+    int width, height;
+    int threed = 0;
+    struct filter *f1 = f;
+
+    inhermisc(f, i);
+    if (datalost(f, i))
+	s->recal = 1;
+    while (f1) {
+	if (f1->action == &threed_filter)
+	    threed = 1;
+	f1 = f1->next;
+    }
+    f->imageversion = i->image->version;
+    if (f->childimage != NULL)
+	destroy_image(f->childimage);
+    s->image = f->image = i->image;
+    s->image->flags |= PROTECTBUFFERS;
+    s->currlines = f->image->currlines;
+    s->forpversion = f->image->palette->version;
+    s->forversion = f->fractalc->version;
+    if (f->image->width * f->image->pixelwidth <
+	f->image->height * f->image->pixelheight)
+	size = f->image->width * f->image->pixelwidth / 2;
+    else
+	size = f->image->height * f->image->pixelheight / 2;
+    width = (int) (size / f->image->pixelwidth);
+    height = (int) (size / f->image->pixelheight);
+    /*fractalc_resize_to(f->fractalc,size,size); */
+    lines1 = (pixel_t **) malloc(sizeof(*lines1) * height);
+    if (f->image->nimages == 2)
+	lines2 = (pixel_t **) malloc(sizeof(*lines2) * height);
+    if (lines1 == NULL)
+	return 0;
+    if (f->image->nimages == 2 && lines2 == NULL) {
+	free(lines1);
+	return 0;
+    }
+    for (x = 0; x < height; x++) {
+	lines1[x] =
+	    i->image->currlines[x + (threed ? f->image->height / 3 : 0)];
+	if (f->image->nimages == 2)
+	    lines2[x] =
+		i->image->oldlines[x +
+				   (threed ? f->image->height / 3 : 0)];
+    }
+    if (f->image->nimages == 2)
+	for (x = 0; x < f->image->height; x++) {
+	    memcpy(f->image->oldlines[x], f->image->currlines[x],
+		   f->image->width * f->image->bytesperpixel);
+	}
+    f->childimage = i->image =
+	create_image_lines(width, height, f->image->nimages, lines1,
+			   lines2, i->image->palette, myflip, FREELINES,
+			   f->image->pixelwidth, f->image->pixelheight);
+    if (i->image == NULL) {
+	free(lines1);
+	free(lines2);
+	return 0;
+    }
+    f->childimage->data = s;
+    x = f->previous->action->initialize(f->previous, i);
+    if (!x)
+	return 0;
+    if (s->second != NULL) {
+	i->image = f->image;
+	val = s->second->action->initialize(s->second, i);
+	if (!val)
+	    return 0;
+    }
+    return (x | val);
+
+}
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    struct subdata *s = (struct subdata *) calloc(1, sizeof(*s));
+    f->name = "Subwindow";
+    f->data = s;
+    s->second = NULL;
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    free(f->data);
+    if (f->childimage != NULL)
+	destroy_image(f->childimage);
+    free(f);
+}
+
+static int doit(struct filter *f, int flags, int time)
+{
+    int val = 0, m, vold;
+    vinfo vs;
+    vrect rs;
+    float wwidth, wheight;
+    struct subdata *s = (struct subdata *) f->data;
+    static int v;
+    if (s->second != NULL
+	&& (s->recal || s->forpversion != f->image->palette->version
+	    || s->forversion != f->fractalc->version)) {
+	int x;
+	if (s->recal)
+	    f->fractalc->version++;
+	s->forpversion = f->image->palette->version;
+	s->forversion = f->fractalc->version;
+	s->recal = 1;
+	val = (s->second->action->doit(s->second, flags, time));
+	if (val & ANIMATION)
+	    return val;
+	s->recal = 0;
+	if (f->image->nimages == 2)
+	    for (x = 0; x < f->image->height; x++) {
+		memcpy(f->image->oldlines[x], f->image->currlines[x],
+		       f->image->width * f->image->bytesperpixel);
+	    }
+    }
+    if (s->currlines != f->image->currlines && f->childimage->nimages == 2)
+	flipgeneric(f->childimage), s->currlines = f->image->currlines;
+    /*FIXME: ugly hack for new julia mode */
+    v++;
+    wwidth = f->fractalc->windowwidth;
+    wheight = f->fractalc->windowheight;
+    f->fractalc->windowwidth =
+	f->previous->image->width * f->previous->image->pixelwidth;
+    f->fractalc->windowheight =
+	f->previous->image->height * f->previous->image->pixelheight;
+    vs = f->fractalc->s;
+    rs = f->fractalc->rs;
+    f->fractalc->s = f->fractalc->currentformula->v;
+    if (f->fractalc->currentformula->calculate_julia) {
+	f->fractalc->s.cr = f->fractalc->s.ci = 0;
+	f->fractalc->s.rr = f->fractalc->s.ri = 4;	/*FIXME should be set to real formula's bailout */
+    }
+    update_view(f->fractalc);
+    m = f->fractalc->mandelbrot;
+    vold = f->fractalc->version;
+    if (s->pre != f->fractalc->pre || s->pim != f->fractalc->pim) {
+	f->fractalc->version = v;
+	s->pre = f->fractalc->pre;
+	s->pim = f->fractalc->pim;
+    }
+    f->fractalc->mandelbrot = 0;
+    val = f->previous->action->doit(f->previous, flags, time) | val;
+    f->fractalc->mandelbrot = m;
+    f->fractalc->version = vold;
+    f->fractalc->s = vs;
+    f->fractalc->rs = rs;
+    f->fractalc->windowwidth = wwidth;
+    f->fractalc->windowheight = wheight;
+    return val;
+}
+
+static void myremove(struct filter *f)
+{
+    /*fractalc_resize_to(f->fractalc,f->queue->last->image->width*f->queue->last->image->pixelwidth,f->queue->last->image->height*f->queue->last->image->pixelheight); */
+}
+
+static void convertdown(struct filter *f, int *x, int *y)
+{
+    struct subdata *s = (struct subdata *) f->data;
+    if (s->second != NULL)
+	s->second->action->convertdown(s->second, x, y);
+    if (f->previous != NULL)
+	f->previous->action->convertdown(f->previous, x, y);
+}
+
+
+CONST struct filteraction subwindow_filter = {
+    "Subwindow",
+    "Subwindow",
+    0,
+    getinstance,
+    destroyinstance,
+    doit,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdown,
+    myremove
+};
diff --git a/src/engine/zoom.c b/src/engine/zoom.c
new file mode 100644
index 0000000..907da95
--- /dev/null
+++ b/src/engine/zoom.c
@@ -0,0 +1,1762 @@
+/* 
+ *     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 DRAW */
+#include 
+#include 
+#ifdef _plan9_
+#include 
+#include 
+#include 
+#else
+#include 
+#include 
+#ifndef _MAC
+#ifndef NO_MALLOC_H
+#include 
+#endif
+#endif
+#ifdef __EMX__
+#include 
+#include 
+#endif
+#include 
+#ifdef HAVE_LIMITS_H
+#include 
+#endif
+#include 
+#include 
+#ifdef HAVE_ALLOCA_H
+#include 
+#endif
+#ifndef _plan9_
+/*#undef NDEBUG */
+#include 
+#endif
+#endif
+#define SLARGEITER
+#include 
+#include 
+#include 
+#include 		/*for myabs */
+#include 
+#include 
+#include 
+#include 
+#include "calculate.h"		/*an inlined calulate function */
+
+#ifdef HAVE_GETTEXT
+#include 
+#else
+#define gettext(STRING) STRING
+#endif
+
+#define ASIZE 16
+#define ALIGN(x) (((x)+ASIZE-1)&(~(ASIZE-1)))
+static int nsymetrized;
+unsigned char *tmpdata, *tmpdata1;
+struct realloc_s {
+    number_t possition;
+    number_t price;
+    unsigned int plus;
+    int recalculate;
+    int symto;
+    int symref;
+    int dirty;
+}
+#ifdef __GNUC__
+__attribute__ ((aligned(32)))
+#endif
+    ;
+typedef struct realloc_s realloc_t;
+
+
+typedef struct zoom_context {
+    number_t *xpos, *ypos;
+    int newcalc;
+    int forversion;
+    int forpversion;
+    realloc_t *reallocx, *reallocy;
+    int uncomplette;
+    int changed;
+} zoom_context;
+
+struct filltable {
+    int from;
+    int to;
+    int length;
+    int end;
+};
+#define getzcontext(f) ((zoom_context *)((f)->data))
+#define getfcontext(f) ((f)->fractalc)
+
+#define callwait() if(cfilter.wait_function!=NULL) cfilter.wait_function(&cfilter);
+#define tcallwait() if(!xth_nthread(task)&&cfilter.wait_function!=NULL) cfilter.wait_function(&cfilter);
+#define setuncomplette(i) (getzcontext(&cfilter)->uncomplette=i)
+#define incuncomplette() (getzcontext(&cfilter)->uncomplette++)
+#define setchanged(i) (getzcontext(&cfilter)->changed=i)
+
+
+zoom_context czoomc;
+struct filter cfilter;
+#ifdef STATISTICS
+static int tocalculate = 0, avoided = 0;
+static int nadded = 0, nsymetry = 0, nskipped = 0;
+int nperi = 0;
+#endif
+
+#ifdef _NEVER_
+#define rdtsc() ({unsigned long long time; asm __volatile__ ("rdtsc":"=A"(time)); time; })
+#define startagi() ({asm __volatile__ ("rdmsr ; andw 0xfe00,%%ax ; orw 0x1f, %%ax ; wrmsr; "::"c"(22):"ax","dx"); })
+#define countagi() ({unsigned long long count; asm __volatile__ ("rdmsr":"=A"(count):"c"(12)); count;})
+#define cli() ({asm __volatile__ ("cli");})
+#define sti() ({asm __volatile__ ("sti");})
+#else
+#define rdtsc() 0
+#define cli() 0
+#define sti() 0
+#define startagi() 0
+#define countagi() 0
+#endif
+
+#ifndef USE_i386ASM
+static void
+moveoldpoints(void *data1, struct taskinfo *task, int r1, int r2)
+REGISTERS(0);
+static void fillline_8(int line) REGISTERS(0);
+static void fillline_16(int line) REGISTERS(0);
+static void fillline_24(int line) REGISTERS(0);
+static void fillline_32(int line) REGISTERS(0);
+#endif
+
+/*first of all inline driver section */
+/*If you think this way is ugly, I must agree. Please let me know
+ *about better one that allows to generate custom code for 8,16,24,32
+ *bpp modes and use of static variables
+ */
+#include 
+#define fillline fillline_8
+#define dosymetry2 dosymetry2_8
+#define calcline calcline_8
+#define calccolumn calccolumn_8
+#include "zoomd.c"
+
+#include 
+#define fillline fillline_32
+#define dosymetry2 dosymetry2_32
+#define calcline calcline_32
+#define calccolumn calccolumn_32
+#include "zoomd.c"
+
+#include 
+#define fillline fillline_24
+#define dosymetry2 dosymetry2_24
+#define calcline calcline_24
+#define calccolumn calccolumn_24
+#include "zoomd.c"
+
+#include 
+#define fillline fillline_16
+#define dosymetry2 dosymetry2_16
+#define calcline calcline_16
+#define calccolumn calccolumn_16
+#include "zoomd.c"
+
+#define calcline(a) drivercall(cimage,calcline_8(a),calcline_16(a),calcline_24(a),calcline_32(a));
+#define calccolumn(a) drivercall(cimage,calccolumn_8(a),calccolumn_16(a),calccolumn_24(a),calccolumn_32(a));
+
+
+struct dyn_data {
+    int price;
+    struct dyn_data *previous;
+};
+
+#define FPMUL 64		/*Let multable fit into pentium cache */
+#define RANGES 2		/*shift equal to x*RANGE */
+#define RANGE 4
+
+#define DSIZEHMASK (0x7)	/*mask equal to x%(DSIZE) */
+#define DSIZE (2*RANGE)
+#define DSIZES (RANGES+1)	/*shift equal to x*DSIZE */
+
+
+#define adddata(n,i) (dyndata+(((n)<=dyndata),assert((pos)symto != -1)
+	    continue;
+
+	fy = realloc->possition;
+	realloc->symto = 2 * symi - i;
+
+	if (realloc->symto >= size - RANGE)
+	    realloc->symto = size - RANGE - 1;
+
+	dist = RANGE * step;
+	min = RANGE;
+#ifndef NDEBUG
+	if (realloc->symto < 0 || realloc->symto >= size) {
+	    x_fatalerror("Internal error #22-1 %i", realloc->symto);
+	    assert(0);
+	}
+#endif
+	reallocs = &r[realloc->symto];
+	j = (realloc->symto - istart >
+	     RANGE) ? -RANGE : (-realloc->symto + istart);
+
+	if (realloc->recalculate) {
+	    for (; j < RANGE && realloc->symto + j < size - 1; j++) {
+		ftmp = sym - (reallocs + j)->possition;
+		if ((tmp1 = myabs(ftmp - fy)) < dist) {
+		    if ((realloc == r || ftmp > (realloc - 1)->possition)
+			&& (ftmp < (realloc + 1)->possition)) {
+			dist = tmp1;
+			min = j;
+		    }
+		} else if (ftmp < fy)
+		    break;
+	    }
+
+	} else {
+	    for (; j < RANGE && realloc->symto + j < size - 1; j++) {
+		if (!realloc->recalculate)
+		    continue;
+		ftmp = sym - (reallocs + j)->possition;
+		if ((tmp1 = myabs(ftmp - fy)) < dist) {
+		    if ((realloc == r || ftmp > (realloc - 1)->possition)
+			&& (ftmp < (realloc + 1)->possition)) {
+			dist = tmp1;
+			min = j;
+		    }
+		} else if (ftmp < fy)
+		    break;
+	    }
+	}
+	realloc->symto += min;
+
+	if (min == RANGE || realloc->symto <= symi ||
+	    (reallocs = reallocs + min)->symto != -1
+	    || reallocs->symref != -1) {
+	    realloc->symto = -1;
+	    continue;
+	}
+
+	if (!realloc->recalculate) {
+	    realloc->symto = -1;
+	    if (reallocs->symto != -1 || !reallocs->recalculate)
+		continue;
+	    reallocs->plus = realloc->plus;
+	    reallocs->symto = i;
+	    nsymetrized++;
+	    istart = realloc->symto - 1;
+	    reallocs->dirty = 1;
+	    realloc->symref = (int) (reallocs - r);
+	    STAT(nadded -= reallocs->recalculate);
+	    reallocs->recalculate = 0;
+	    reallocs->possition = sym - realloc->possition;
+	} else {
+	    if (reallocs->symto != -1) {
+		realloc->symto = -1;
+		continue;
+	    }
+	    istart = realloc->symto - 1;
+	    STAT(nadded -= realloc->recalculate);
+	    nsymetrized++;
+	    realloc->dirty = 1;
+	    realloc->plus = reallocs->plus;
+	    realloc->recalculate = 0;
+	    reallocs->symref = i;
+	    realloc->possition = sym - reallocs->possition;
+	}
+	STAT(nsymetry++);
+
+#ifndef NDEBUG
+	if (realloc->symto < -1 || realloc->symto >= size) {
+	    x_fatalerror("Internal error #22 %i", realloc->symto);
+	    assert(0);
+	}
+	if (reallocs->symto < -1 || reallocs->symto >= size) {
+	    x_fatalerror("Internal error #22-2 %i", reallocs->symto);
+	    assert(0);
+	}
+#endif
+    }
+
+}
+
+static /*INLINE */ void
+newpossitions(realloc_t * realloc, unsigned int size, number_t begin1,
+	      number_t end1, CONST number_t * fpos, int yend)
+{
+    realloc_t *rs, *re, *rend;
+    number_t step = size / (end1 - begin1);
+    number_t start;
+    number_t end;
+    rend = realloc + size;
+    rs = realloc - 1;
+    re = realloc;
+    while (rs < rend - 1) {
+	re = rs + 1;
+	if (re->recalculate) {
+	    while (re < rend && re->recalculate)
+		re++;
+
+	    if (re == rend)
+		end = end1;
+	    else
+		end = re->possition;
+
+	    if (rs == realloc - 1) {
+		start = begin1;
+		if (start > end)
+		    start = end;
+	    } else
+		start = rs->possition;
+
+	    if (re == rend && start > end)
+		end = start;
+
+	    if (re - rs == 2)
+		end = (end - start) * 0.5;
+	    else
+		end = ((number_t) (end - start)) / (re - rs);
+
+
+	    switch (yend) {
+	    case 1:
+		for (rs++; rs < re; rs++) {
+		    start += end, rs->possition = start;
+		    rs->price =
+			1 / (1 + myabs(fpos[rs - realloc] - start) * step);
+		}
+		break;
+	    case 2:
+		for (rs++; rs < re; rs++) {
+		    start += end, rs->possition = start;
+		    rs->price = (myabs(fpos[rs - realloc] - start) * step);
+		    if (rs == realloc || rs == rend - 1)
+			rs->price *= 500;
+		}
+		break;
+	    default:
+		for (rs++; rs < re; rs++) {
+		    start += end, rs->possition = start;
+		    rs->price = (number_t) 1;
+		}
+		break;
+	    }
+	}
+	rs = re;
+    }
+}
+
+/* This is the main reallocation algorithm described in xaos.info
+ * It is quite complex since many loops are unrooled and uses custom
+ * fixedpoint
+ *
+ * Takes approx 30% of time so looking for way to do it threaded.
+ * Let me know :)
+ */
+static /*INLINE */ void
+mkrealloc_table(CONST number_t * RESTRICT fpos,
+		realloc_t * RESTRICT realloc,
+		CONST unsigned int size, CONST number_t begin,
+		CONST number_t end, number_t sym, unsigned char *tmpdata)
+{
+    unsigned int i;
+    int counter;
+    unsigned int ps, ps1 = 0, pe;
+    register unsigned int p;
+    int bestprice = MAXPRICE;
+    realloc_t *r = realloc;
+    struct dyn_data *RESTRICT dyndata;
+    int yend, y;
+    register struct dyn_data **RESTRICT best;
+    struct dyn_data **RESTRICT best1, **tmp;
+    register int *RESTRICT pos;
+    number_t step, tofix;
+    int symi = -1;
+    unsigned int lastplus = 0;
+    struct dyn_data *RESTRICT data;
+    register struct dyn_data *previous = NULL, *bestdata = NULL;
+    register int myprice;
+#ifdef STATISTICS
+    nadded = 0, nsymetry = 0, nskipped = 0;
+#endif
+
+    pos = (int *) tmpdata;
+    best =
+	(struct dyn_data **) (tmpdata + ALIGN((size + 2) * sizeof(int)));
+    best1 =
+	(struct dyn_data **) (tmpdata + ALIGN((size + 2) * sizeof(int)) +
+			      ALIGN(size * sizeof(struct dyn_data **)));
+    dyndata =
+	(struct dyn_data *) (tmpdata + ALIGN((size + 2) * sizeof(int)) +
+			     2 * ALIGN(size * sizeof(struct dyn_data **)));
+
+    tofix = size * FPMUL / (end - begin);
+    pos[0] = INT_MIN;
+    pos++;
+    for (counter = (int) size - 1; counter >= 0; counter--) {
+	pos[counter] = (int) ((fpos[counter] - begin) * tofix);	/*first convert everything into fixedpoint */
+	if (counter < (int) size - 1 && pos[counter] > pos[counter + 1])
+	    /*Avoid processing of missordered rows.
+	       They should happend because of limited
+	       precisity of FP numbers */
+	    pos[counter] = pos[counter + 1];
+    }
+    pos[size] = INT_MAX;
+    step = (end - begin) / (number_t) size;
+    if (begin > sym || sym > end)	/*calculate symetry point */
+	symi = -2;
+    else {
+	symi = (int) ((sym - begin) / step);
+
+    }
+
+    ps = 0;
+    pe = 0;
+    y = 0;
+
+    /* This is first pass that fills table dyndata, that holds information
+     * about all ways algorithm thinks about. Correct way is discovered at
+     * end by looking backward and determining witch way algorithm used to
+     * calculate minimal value*/
+
+    for (i = 0; i < size; i++, y += FPMUL) {
+	bestprice = MAXPRICE;
+	p = ps;			/*just inicialize parameters */
+
+	tmp = best1;
+	best1 = best;
+	best = tmp;
+
+	yend = y - IRANGE;
+	if (yend < -FPMUL)	/*do no allow lines outside screen */
+	    yend = -FPMUL;
+
+	while (pos[p] <= yend)	/*skip lines out of range */
+	    p++;
+#ifdef _UNDEFINED_
+	if (pos[p - 1] > yend)	/*warning...maybe this is the bug :) */
+	    p--, assert(0);
+#endif
+	ps1 = p;
+	yend = y + IRANGE;
+
+	/*First try case that current line will be newly calculated */
+
+	/*Look for best way how to connect previous lines */
+	if (ps != pe && p > ps) {	/*previous point had lines */
+	    assert(p >= ps);
+	    if (p < pe) {
+		previous = best[p - 1];
+		CHECKPOS(previous);
+	    } else
+		previous = best[pe - 1];
+	    CHECKPOS(previous);
+	    myprice = previous->price;	/*find best one */
+	} else {
+	    if (i > 0) {	/*previous line had no lines */
+		previous = getbest(i - 1);
+		myprice = previous->price;
+	    } else
+		previous = END, myprice = 0;
+	}
+
+	data = getbest(i);	/*find store possition */
+	myprice += NEWPRICE;
+	bestdata = data;
+	data->previous = previous;
+	bestprice = myprice;	/*calculate best available price */
+	data->price = myprice;	/*store data */
+	assert(bestprice >= 0);	/*FIXME:tenhle assert muze FAILIT! */
+#ifdef _UNDEFINED_
+	if (yend > end + FPMUL)	/*check bounds */
+	    yend = end + FPMUL;
+#endif
+	data = adddata(p, i);	/*calcualte all lines good for this y */
+
+	/* Now try all acceptable connection and calculate best possibility
+	 * with this connection
+	 */
+	if (ps != pe) {		/*in case that previous had also possitions */
+	    int price1 = INT_MAX;
+	    /*At first line of previous interval we have only one possibility
+	     *don't connect previous line at all.
+	     */
+	    if (p == ps) {	/*here we must skip previous point */
+		if (pos[p] != pos[p + 1]) {
+		    previous = getbest(i - 1);
+		    myprice = previous->price;
+		    myprice += PRICE(pos[p], y);	/*store data */
+		    if (myprice < bestprice) {	/*calcualte best */
+			bestprice = myprice, bestdata = data;
+			data->price = myprice;
+			data->previous = previous;
+		    }
+		}
+		assert(bestprice >= 0);
+		assert(myprice >= 0);
+		best1[p] = bestdata;
+		data += DSIZE;
+		p++;
+	    }
+
+	    previous = NULL;
+	    price1 = myprice;
+	    while (p < pe) {	/*this is area where intervals of current point and previous one are crossed */
+		if (pos[p] != pos[p + 1]) {
+		    if (previous != best[p - 1]) {
+
+			previous = best[p - 1];
+			CHECKPOS(previous);
+			price1 = myprice = previous->price;
+
+			/*In case we found revolutional point, we should think
+			 *about changing our gusesses in last point too - don't
+			 *connect it at all, but use this way instead*/
+			if (myprice + NEWPRICE < bestprice) {	/*true in approx 2/3 of cases */
+			    bestprice = myprice + NEWPRICE, bestdata =
+				data - DSIZE;
+			    (bestdata)->price = bestprice;
+			    (bestdata)->previous = previous + nosetadd;
+			    best1[p - 1] = bestdata;
+			}
+		    } else
+			myprice = price1;
+
+		    myprice += PRICE(pos[p], y);	/*calculate price of new connection */
+
+		    if (myprice < bestprice) {	/*2/3 of cases *//*if it is better than previous, store it */
+			bestprice = myprice, bestdata = data;
+			data->price = myprice;
+			data->previous = previous;
+		    } else if (pos[p] > y) {
+			best1[p] = bestdata;
+			data += DSIZE;
+			p++;
+			break;
+		    }
+
+		}
+
+		assert(myprice >= 0);
+		assert(bestprice >= 0);	/*FIXME:tenhle assert FAILI! */
+
+		best1[p] = bestdata;
+		data += DSIZE;
+		p++;
+	    }
+	    while (p < pe) {	/*this is area where intervals of current point and previous one are crossed */
+#ifdef DEBUG
+		if (pos[p] != pos[p + 1]) {
+		    if (previous != best[p - 1]) {
+			x_fatalerror("Missoptimization found!");
+		    }
+		}
+#endif
+#ifdef _UNDEFINED_
+		/* Experimental results show, that probability for better approximation
+		 * in this area is extremly low. Maybe it never happends. 
+		 * I will have to think about it a bit more... It seems to have
+		 * to do something with meaning of universe and god... no idea
+		 * why it is true.
+		 *
+		 * Anyway it don't seems to worth include the expensive tests
+		 * here.
+		 */
+		if (pos[p] != pos[p + 1]) {
+		    if (previous != best[p - 1]) {
+
+			previous = best[p - 1];
+			CHECKPOS(previous);
+			myprice = previous->price;
+
+			/*In case we found revolutional point, we should think
+			 *about changing our gusesses in last point too - don't
+			 *connect it at all, but use this way instead*/
+			if (myprice + NEWPRICE < bestprice) {	/*true in approx 2/3 of cases */
+			    bestprice = myprice + NEWPRICE, bestdata =
+				data - DSIZE;
+			    (bestdata)->price = bestprice;
+			    (bestdata)->previous = previous + nosetadd;
+			    best1[p - 1] = bestdata;
+			}
+			myprice += PRICE(pos[p], y);	/*calculate price of new connection */
+			if (myprice < bestprice) {	/*if it is better than previous, store it */
+			    bestprice = myprice, bestdata = data;
+			    data->price = myprice;
+			    data->previous = previous;
+			}
+		    }
+		}
+#endif
+		assert(myprice >= 0);
+		assert(bestprice >= 0);	/*FIXME:tenhle assert FAILI! */
+
+		best1[p] = bestdata;
+		data += DSIZE;
+		p++;
+	    }
+
+	    /* OK...we passed crossed area. All next areas have same previous
+	     * situation so our job is easier
+	     * So find the best solution once for all od them
+	     */
+	    if (p > ps) {
+		previous = best[p - 1];	/*find best one in previous */
+		CHECKPOS(previous);
+		price1 = previous->price;
+	    } else {
+		previous = getbest(i - 1);
+		price1 = previous->price;
+	    }
+
+	    /* Since guesses for "revolutional point" was allways one
+	     * step back, we need to do last one*/
+	    if (price1 + NEWPRICE < bestprice && p > ps1) {
+		myprice = price1 + NEWPRICE;
+		bestprice = myprice, bestdata = data - DSIZE;
+		(bestdata)->price = myprice;
+		(bestdata)->previous = previous + nosetadd;
+		best1[p - 1] = bestdata;
+		myprice -= NEWPRICE;
+	    }
+
+	    while (pos[p] < yend) {
+		if (pos[p] != pos[p + 1]) {
+		    myprice = price1;
+		    myprice += PRICE(pos[p], y);	/*store data */
+		    if (myprice < bestprice) {	/*calcualte best */
+			bestprice = myprice, bestdata = data;
+			data->price = myprice;
+			data->previous = previous;
+		    } else if (pos[p] > y)
+			break;
+		}
+
+		assert(bestprice >= 0);
+		assert(myprice >= 0);
+
+		best1[p] = bestdata;
+		data += DSIZE;
+		p++;
+	    }
+	    while (pos[p] < yend) {
+		best1[p] = bestdata;
+		p++;
+	    }
+	} else {
+	    /* This is second case - previous y was not mapped at all.
+	     * Situation is simplier now, since we know that behind us is
+	     * large hole and our decisions don't affect best solution for
+	     * previous problem. Se we have just one answer
+	     * Situation is similiar to latest loop in previous case
+	     */
+	    int myprice1;	/*simplified loop for case that previous
+				   y had no lines */
+	    if (pos[p] < yend) {
+		if (i > 0) {
+		    previous = getbest(i - 1);
+		    myprice1 = previous->price;
+		} else
+		    previous = END, myprice1 = 0;
+		while (pos[p] < yend) {
+		    if (pos[p] != pos[p + 1]) {
+			myprice = myprice1 + PRICE(pos[p], y);
+			if (myprice < bestprice) {
+			    data->price = myprice;
+			    data->previous = previous;
+			    bestprice = myprice, bestdata = data;
+			} else if (pos[p] > y)
+			    break;
+		    }
+		    assert(bestprice >= 0);
+		    assert(myprice >= 0);
+		    best1[p] = bestdata;
+		    p++;
+		    data += DSIZE;
+		}
+		while (pos[p] < yend) {
+		    best1[p] = bestdata;
+		    p++;
+		}
+	    }
+	}
+	/*previous = ps; *//*store possitions for next loop */
+	ps = ps1;
+	ps1 = pe;
+	pe = p;
+    }
+
+
+    assert(bestprice >= 0);
+
+    realloc = realloc + size;
+    yend = (int) ((begin > fpos[0]) && (end < fpos[size - 1]));
+
+    if (pos[0] > 0 && pos[size - 1] < (int) size * FPMUL)
+	yend = 2;
+
+
+
+    /*This part should be made threaded quite easily...but does it worth
+     *since it is quite simple loop 0...xmax
+     */
+    for (i = size; i > 0;) {	/*and finally traces the path */
+	struct dyn_data *bestdata1;
+	realloc--;
+	i--;
+	realloc->symto = -1;
+	realloc->symref = -1;
+	bestdata1 = bestdata->previous;
+
+	if (bestdata1 >= dyndata + nosetadd
+	    || bestdata >= dyndata + ((size) << DSIZES)) {
+	    if (bestdata1 >= dyndata + nosetadd)
+		bestdata1 -= nosetadd;
+
+	    realloc->recalculate = 1;
+	    STAT(nadded++);
+	    realloc->dirty = 1;
+	    lastplus++;
+
+	    if (lastplus >= size)
+		lastplus = 0;
+
+	    realloc->plus = lastplus;
+
+	} else {
+	    p = ((unsigned int) (bestdata - dyndata)) >> DSIZES;
+	    assert(p >= 0 && p < size);
+	    realloc->possition = fpos[p];
+	    realloc->plus = p;
+	    realloc->dirty = 0;
+	    realloc->recalculate = 0;
+	    lastplus = p;
+	}
+	bestdata = bestdata1;
+    }
+
+
+
+    newpossitions(realloc, size, begin, end, fpos, yend);
+    realloc = r;
+    if (symi <= (int) size && symi >= 0) {
+	preparesymetries(r, (int) size, symi, sym, step);
+    }
+
+
+    STAT(printf
+	 ("%i added %i skipped %i mirrored\n", nadded, nskipped,
+	  nsymetry));
+    STAT(nadded2 += nadded;
+	 nskipped2 += nskipped;
+	 nsymetry2 += nsymetry);
+}
+
+struct movedata {
+    unsigned int size;
+    unsigned int start;
+    unsigned int plus;
+};
+int avgsize;
+/* 
+ * this function prepares fast moving table for moveoldpoints
+ * see xaos.info for details. It is not threaded since it is quite
+ * fast.
+ */
+static /*INLINE */ void preparemoveoldpoints(void)
+{
+    struct movedata *data, *sizend;
+    realloc_t *rx, *rx1, *rend1;
+    int sum = 0, num = 0;
+    int plus1 = 0;
+
+    data = (struct movedata *) tmpdata;
+    for (rx = czoomc.reallocx, rend1 = rx + cimage.width; rx < rend1; rx++)
+	if ((rx->dirty) && plus1 < cimage.width + 1)
+	    plus1++;
+	else
+	    break;
+    data->start = czoomc.reallocx->plus;
+    data->size = 0;
+    data->plus = plus1;
+    rend1--;
+    while (rend1->dirty) {
+	if (rend1 == czoomc.reallocx)
+	    return;
+	rend1--;
+    }
+    rend1++;
+    for (; rx < rend1; rx++) {
+	if ((rx->dirty || rx->plus == data->start + data->size))
+	    data->size++;
+	else {
+	    if (data->size) {
+		plus1 = 0;
+		rx1 = rx - 1;
+		while (rx1 > czoomc.reallocx && rx1->dirty)
+		    plus1++, data->size--, rx1--;
+		if (!
+		    (data->start + data->size <
+		     (unsigned int) cimage.width)
+&& !rx->dirty) {
+		    int i;
+		    if (rx == rend1)
+			break;
+		    for (i = 0; rx->dirty && rx < rend1; rx++)
+			i++;
+		    data++;
+		    data->plus = plus1;
+		    data->size = (unsigned int) i;
+		    data->start = rx->plus - i;
+		} else {
+		    sum += data->size;
+		    num++;
+		    data++;
+		    data->plus = plus1;
+		    data->start = rx->plus;
+		}
+	    } else
+		data->start = rx->plus;
+	    assert(rx->plus >= 0
+		   && rx->plus < (unsigned int) cimage.width);
+	    data->size = 1;
+	}
+
+    }
+    if (data->size) {
+	sizend = data + 1;
+	sum += data->size;
+	rx1 = rx - 1;
+	while (rx1 > czoomc.reallocx && rx1->dirty)
+	    data->size--, rx1--;
+	num++;
+    } else
+	sizend = data;
+    sizend->size = 0;
+    if (cimage.bytesperpixel != 1) {
+	sum *= cimage.bytesperpixel;
+	for (data = (struct movedata *) tmpdata; data < sizend; data++) {
+	    data->plus *= cimage.bytesperpixel;
+	    data->size *= cimage.bytesperpixel;
+	    data->start *= cimage.bytesperpixel;
+	}
+    }
+    if (num)
+	avgsize = sum / num;
+}
+
+#ifndef USE_i386ASM
+static /*INLINE */ void
+moveoldpoints(void /*@unused@ */ *data1,
+	      struct taskinfo /*@unused@ */ *task,
+	      int r1, int r2)
+{
+    struct movedata *data;
+    register unsigned char *vline, *vbuff;
+    realloc_t *ry, *rend;
+    int i = r1;
+
+    for (ry = czoomc.reallocy + r1, rend = czoomc.reallocy + r2; ry < rend;
+	 ry++, i++) {
+	if (!ry->dirty) {
+	    assert(ry->plus >= 0
+		   && ry->plus < (unsigned int) cimage.height);
+	    vbuff = cimage.currlines[i];
+	    vline = cimage.oldlines[ry->plus];
+	    for (data = (struct movedata *) tmpdata; data->size; data++) {
+		vbuff += data->plus;
+		memcpy(vbuff, vline + data->start, (size_t) data->size),
+		    vbuff += data->size;
+	    }
+	}
+    }
+}
+#endif
+/* This function prepares fast filling tables for fillline */
+static /*INLINE */ int mkfilltable(void)
+{
+    int vsrc;
+    int pos;
+    realloc_t *rx, *r1, *r2, *rend, *rend2;
+    int n = 0;
+    int num = 0;
+    struct filltable *tbl = (struct filltable *) tmpdata;
+
+    pos = 0;
+    vsrc = 0;
+
+    rx = czoomc.reallocx;
+    while (rx > czoomc.reallocx && rx->dirty)
+	rx--;
+    for (rend = czoomc.reallocx + cimage.width, rend2 =
+	 czoomc.reallocx + cimage.width; rx < rend; rx++) {
+	if (rx->dirty) {
+	    r1 = rx - 1;
+	    for (r2 = rx + 1; r2 < rend2 && r2->dirty; r2++);
+	    while (rx < rend2 && rx->dirty) {
+		n = (int) (r2 - rx);
+		assert(n > 0);
+		if (r2 < rend2
+		    && (r1 < czoomc.reallocx
+			|| rx->possition - r1->possition >
+			r2->possition - rx->possition))
+		    vsrc = (int) (r2 - czoomc.reallocx), r1 = r2;
+		else {
+		    vsrc = (int) (r1 - czoomc.reallocx);
+		    if (vsrc < 0)
+			goto end;
+		}
+		pos = (int) (rx - czoomc.reallocx);
+		assert(pos >= 0 && pos < cimage.width);
+		assert(vsrc >= 0 && vsrc < cimage.width);
+
+		tbl[num].length = n;
+		tbl[num].to = pos * cimage.bytesperpixel;
+		tbl[num].from = vsrc * cimage.bytesperpixel;
+		tbl[num].end =
+		    tbl[num].length * cimage.bytesperpixel + tbl[num].to;
+		/*printf("%i %i %i %i\n",num,tbl[num].length, tbl[num].to, tbl[num].from); */
+		while (n) {
+		    rx->possition = czoomc.reallocx[vsrc].possition;
+		    rx->dirty = 0;
+		    rx++;
+		    n--;
+		}
+		num++;
+	    }			/*while rx->dirty */
+	}			/*if rx->dirty */
+    }				/*for czoomc */
+  end:
+    tbl[num].length = 0;
+    tbl[num].to = pos;
+    tbl[num].from = vsrc;
+    return num;
+}
+
+static /*INLINE */ void filly(void	/*@unused@ */
+			      /*@null@ */ *data,
+			      struct taskinfo /*@unused@ */ *task, int rr1,
+			      int rr2)
+{
+    register unsigned char **vbuff = cimage.currlines;
+    realloc_t *ry, *r1, *r2, *rend, *rend2, *rs = NULL;
+    int linesize = cimage.width * cimage.bytesperpixel;
+
+    ry = czoomc.reallocy + rr1;
+
+    ry = czoomc.reallocy + rr1;
+    while (ry > czoomc.reallocy && ry->dirty > 0)
+	ry--;
+    for (rend = czoomc.reallocy + rr2, rend2 =
+	 czoomc.reallocy + cimage.height; ry < rend; ry++) {
+	if (ry->dirty > 0) {
+	    incuncomplette();
+	    r1 = ry - 1;
+	    for (r2 = ry + 1; r2 < rend2 && r2->dirty > 0; r2++);
+#ifdef _UNDEFINED_
+	    if (r2 >= rend && (rr2 != cimage.height || ry == 0))
+#else
+	    if (r2 >= rend2 && (rr2 != cimage.height || ry == 0))
+#endif
+		return;
+	    while (ry < rend2 && ry->dirty > 0) {
+		if (r1 < czoomc.reallocy) {
+		    rs = r2;
+		    if (r2 >= rend2)
+			return;
+		} else if (r2 >= rend2)
+		    rs = r1;
+		else if (ry->possition - r1->possition <
+			 r2->possition - ry->possition)
+		    rs = r1;
+		else
+		    rs = r2;
+		if (!rs->dirty) {
+		    drivercall(cimage,
+			       fillline_8(rs - czoomc.reallocy),
+			       fillline_16(rs - czoomc.reallocy),
+			       fillline_24(rs - czoomc.reallocy),
+			       fillline_32(rs - czoomc.reallocy));
+		    ry->dirty = -1;
+		}
+		memcpy(vbuff[ry - czoomc.reallocy],
+		       vbuff[rs - czoomc.reallocy], (size_t) linesize);
+		ry->possition = rs->possition;
+		ry->dirty = -1;
+		ry++;
+	    }
+	}
+	if (ry < rend && !ry->dirty) {
+	    drivercall(cimage,
+		       fillline_8(ry - czoomc.reallocy),
+		       fillline_16(ry - czoomc.reallocy),
+		       fillline_24(ry - czoomc.reallocy),
+		       fillline_32(ry - czoomc.reallocy));
+	    ry->dirty = -1;
+	}
+    }
+}
+
+static void fill(void)
+{
+    if (cfilter.interrupt) {
+	cfilter.pass = "reducing resolution";
+	mkfilltable();
+	xth_function(filly, NULL, cimage.height);
+    }
+    xth_sync();
+}
+
+static /*INLINE */ void
+calculatenew(void /*@unused@ */ *data, struct taskinfo /*@unused@ */ *task,
+	     int /*@unused@ */ r1, int /*@unused@ */ r2)
+{
+    int s;
+    int i, y;
+    realloc_t *rx, *ry, *rend;
+    int range = cfractalc.range * 2;
+    int positions[16];
+    int calcpositions[16];
+    /*int s3; */
+    if (range < 1)
+	range = 1;
+    if (range > 16)
+	range = 16;
+    memset(positions, 0, sizeof(positions));
+    calcpositions[0] = 0;
+    positions[0] = 1;
+    for (s = 1; s < range;) {
+	for (i = 0; i < range; i++) {
+	    if (!positions[i]) {
+		for (y = i; y < range && !positions[y]; y++);
+		positions[(y + i) / 2] = 1;
+		calcpositions[s++] = (y + i) / 2;
+	    }
+	}
+    }
+
+    if (!xth_nthread(task)) {
+	STAT(tocalculate = 0);
+	STAT(avoided = 0);
+	cfilter.pass = gettext("Solid guessing 1");
+	cfilter.max = 0;
+	cfilter.pos = 0;
+    }
+
+    /* We don't need to wory about race conditions here, since only
+     * problem that should happend is incorrectly counted number
+     * of lines to do...
+     *
+     * I will fix that problem later, but I think that this information
+     * should be quite useless at multithreaded systems so it should
+     * be a bit inaccurate. Just need to take care in percentage
+     * displayers that thinks like -100% or 150% should happend
+     */
+    if (!xth_nthread(task)) {
+	for (ry = czoomc.reallocy, rend = ry + cimage.height; ry < rend;
+	     ry++) {
+	    if (ry->recalculate)
+		cfilter.max++;
+	}
+	for (rx = czoomc.reallocx, rend = rx + cimage.width; rx < rend;
+	     rx++) {
+	    if (rx->recalculate) {
+		cfilter.max++;
+	    }
+	}
+    }
+    tcallwait();
+    for (s = 0; s < range; s++) {
+	for (ry = czoomc.reallocy + calcpositions[s], rend =
+	     czoomc.reallocy + cimage.height; ry < rend; ry += range) {
+	    xth_lock(0);
+	    if (ry->recalculate == 1) {
+		ry->recalculate = 2;
+		xth_unlock(0);
+		setchanged(1);
+		ry->dirty = 0;
+		calcline(ry);
+		cfilter.pos++;
+#ifndef DRAW
+		tcallwait();
+#endif
+		if (cfilter.interrupt) {
+		    break;
+		}
+	    } else {
+		xth_unlock(0);
+	    }
+	}			/*for ry */
+	for (rx = czoomc.reallocx + calcpositions[s], rend =
+	     czoomc.reallocx + cimage.width; rx < rend; rx += range) {
+	    xth_lock(1);
+	    if (rx->recalculate == 1) {
+		rx->recalculate = 2;
+		xth_unlock(1);
+		setchanged(1);
+		rx->dirty = 0;
+		calccolumn(rx);
+		cfilter.pos++;
+#ifndef DRAW
+		tcallwait();
+#endif
+		if (cfilter.interrupt) {
+		    return;
+		}
+	    } else {
+		xth_unlock(1);
+	    }
+	}
+    }
+    STAT(printf
+	 ("Avoided caluclating of %i points from %i and %2.2f%% %2.2f%%\n",
+	  avoided, tocalculate, 100.0 * (avoided) / tocalculate,
+	  100.0 * (tocalculate - avoided) / cimage.width / cimage.height));
+    STAT(avoided2 += avoided;
+	 tocalculate2 += tocalculate;
+	 frames2 += 1);
+}
+
+static void addprices(realloc_t * r, realloc_t * r2) REGISTERS(3);
+REGISTERS(3)
+static void addprices(realloc_t * r, realloc_t * r2)
+{
+    realloc_t *r3;
+    while (r < r2) {
+	r3 = r + (((unsigned int) (r2 - r)) >> 1);
+	r3->price = (r2->possition - r3->possition) * (r3->price);
+	if (r3->symref != -1)
+	    r3->price = r3->price / 2;
+	addprices(r, r3);
+	r = r3 + 1;
+    }
+}
+
+/* We can't do both symetryies (x and y) in one loop at multithreaded
+ * systems,since we need to take care to points at the cross of symetrized
+ * point/column
+ */
+static /*INLINE */ void
+dosymetry(void /*@unused@ */ *data, struct taskinfo /*@unused@ */ *task,
+	  int r1, int r2)
+{
+    unsigned char **vbuff = cimage.currlines + r1;
+    realloc_t *ry, *rend;
+    int linesize = cimage.width * cimage.bytesperpixel;
+
+    for (ry = czoomc.reallocy + r1, rend = czoomc.reallocy + r2; ry < rend;
+	 ry++) {
+	assert(ry->symto >= 0 || ry->symto == -1);
+	if (ry->symto >= 0) {
+	    assert(ry->symto < cimage.height);
+	    if (!czoomc.reallocy[ry->symto].dirty) {
+		memcpy(*vbuff, cimage.currlines[ry->symto],
+		       (size_t) linesize);
+		ry->dirty = 0;
+	    }
+	}
+	vbuff++;
+    }
+}
+
+/*Well, clasical simple quicksort. Should be faster than library one
+ *because of reduced number of function calls :)
+ */
+static INLINE void myqsort(realloc_t ** start, realloc_t ** end)
+{
+    number_t med;
+    realloc_t **left = start, **right = end - 1;
+    while (1) {
+
+	/*Quite strange caluclation of median, but should be
+	 *as good as Sedgewick middle of three method and is faster*/
+	med = ((*start)->price + (*(end - 1))->price) * 0.5;
+
+	/*Avoid one comparsion */
+	if (med > (*start)->price) {
+	    realloc_t *tmp;
+	    tmp = *left;
+	    *left = *right;
+	    *right = tmp;
+	}
+	right--;
+	left++;
+
+	while (1) {
+	    realloc_t *tmp;
+
+	    while (left < right && (*left)->price > med)
+		left++;
+	    while (left < right && med > (*right)->price)
+		right--;
+
+	    if (left < right) {
+		tmp = *left;
+		*left = *right;
+		*right = tmp;
+		left++;
+		right--;
+	    } else
+		break;
+	}
+	if (left - start > 1)
+	    myqsort(start, left);
+	if (end - right <= 2)
+	    return;
+	left = start = right;
+	right = end - 1;
+    }
+}
+
+static int tocalcx, tocalcy;
+static void processqueue(void *data, struct taskinfo /*@unused@ */ *task,
+			 int /*@unused@ */ r1, int /*@unused@ */ r2)
+{
+    realloc_t **tptr = (realloc_t **) data, **tptr1 =
+	(realloc_t **) tmpdata;
+    realloc_t *r, *end;
+    end = czoomc.reallocx + cimage.width;
+
+    while (tptr1 < tptr
+	   && (!cfilter.interrupt || tocalcx == cimage.width
+	       || tocalcy == cimage.height)) {
+	xth_lock(0);
+	r = *tptr1;
+	if (r != NULL) {
+	    *tptr1 = NULL;
+	    xth_unlock(0);
+	    cfilter.pos++;
+	    if (tocalcx < cimage.width - 2 && tocalcy < cimage.height - 2)
+		cfilter.readyforinterrupt = 1;
+	    tcallwait();
+	    if (r >= czoomc.reallocx && r < end) {
+		r->dirty = 0;
+		tocalcx--;
+		calccolumn(r);
+	    } else {
+		r->dirty = 0;
+		tocalcy--;
+		calcline(r);
+	    }
+	} else {
+	    xth_unlock(0);
+	}
+	tptr1++;
+    }
+}
+
+/*
+ * Another long unthreaded code. It seems to be really long and
+ * ugly, but believe or not it takes just about 4% of calculation time,
+ * so why to worry about? :)
+ *
+ * This code looks for columns/lines to calculate, adds them into queue,
+ * sorts it in order of significancy and then calls parrel processqueue,
+ * that does the job.
+ */
+static void calculatenewinterruptible(void)
+{
+    realloc_t *r, *r2, *end, *end1;
+    realloc_t **table, **tptr;
+
+    /*tptr = table = (realloc_t **) malloc (sizeof (*table) * (cimage.width + cimage.height)); */
+    tptr = table = (realloc_t **) tmpdata;
+    end = czoomc.reallocx + cimage.width;
+    tocalcx = 0, tocalcy = 0;
+
+    STAT(tocalculate = 0);
+    STAT(avoided = 0);
+
+    cfilter.pass = gettext("Solid guessing");
+
+    for (r = czoomc.reallocx; r < end; r++)
+	if (r->dirty)
+	    tocalcx++, setchanged(1);
+
+    for (r = czoomc.reallocx; r < end; r++) {
+	if (r->recalculate) {
+	    for (r2 = r; r2 < end && r2->recalculate; r2++)
+		*(tptr++) = r2;
+	    if (r2 == end)
+		/*(r2 - 1)->price = 0, */
+		r2--;
+	    addprices(r, r2);
+	    r = r2;
+	}
+    }
+
+    end1 = czoomc.reallocy + cimage.height;
+
+    for (r = czoomc.reallocy; r < end1; r++)
+	if (r->dirty)
+	    tocalcy++, setchanged(1);
+
+    for (r = czoomc.reallocy; r < end1; r++) {
+	if (r->recalculate) {
+	    for (r2 = r; r2 < end1 && r2->recalculate; r2++)
+		*(tptr++) = r2;
+	    if (r2 == end1)
+		/*(r2 - 1)->price = 0, */
+		r2--;
+	    addprices(r, r2);
+	    r = r2;
+	}
+    }
+    if (table != tptr) {
+
+	if (tptr - table > 1)
+	    myqsort(table, tptr);
+
+	cfilter.pos = 0;
+	cfilter.max = (int) (tptr - table);
+	cfilter.incalculation = 1;
+	callwait();
+
+	xth_function(processqueue, tptr, 1);
+
+	callwait();
+    }
+
+    cfilter.pos = 0;
+    cfilter.max = 0;
+    cfilter.pass = "Procesing symetries";
+    cfilter.incalculation = 0;
+    callwait();
+
+    xth_sync();
+    if (nsymetrized) {
+	xth_function(dosymetry, NULL, cimage.height);
+	xth_sync();
+	drivercall(cimage,
+		   xth_function(dosymetry2_8, NULL, cimage.width),
+		   xth_function(dosymetry2_16, NULL, cimage.width),
+		   xth_function(dosymetry2_24, NULL, cimage.width),
+		   xth_function(dosymetry2_32, NULL, cimage.width));
+	xth_sync();
+    }
+    if (cfilter.interrupt) {
+	cfilter.pass = "reducing resolution";
+	mkfilltable();
+	xth_function(filly, NULL, cimage.height);
+    }
+    xth_sync();
+
+    STAT(printf
+	 ("Avoided caluclating of %i points from %i and %2.2f%% %2.2f%%\n",
+	  avoided, tocalculate, 100.0 * (avoided) / tocalculate,
+	  100.0 * (tocalculate - avoided) / cimage.width / cimage.height));
+    STAT(avoided2 += avoided;
+	 tocalculate2 += tocalculate;
+	 frames2 += 1);
+}
+
+static void init_tables(struct filter *f)
+{
+    int i;
+    zoom_context *c = getzcontext(f);
+
+    /*c->dirty = 2; */
+    for (i = 0; i < f->image->width + 1; i++)
+	c->xpos[i] =
+	    (-f->fractalc->rs.nc + f->fractalc->rs.mc) +
+	    f->fractalc->rs.mc;
+    for (i = 0; i < f->image->height + 1; i++)
+	c->ypos[i] =
+	    (-f->fractalc->rs.ni + f->fractalc->rs.mi) +
+	    f->fractalc->rs.mi;
+}
+
+
+static int alloc_tables(struct filter *f)
+{
+    zoom_context *c = getzcontext(f);
+    c->xpos =
+	(number_t *) malloc((f->image->width + 8) * sizeof(*c->xpos));
+    if (c->xpos == NULL)
+	return 0;
+    c->ypos =
+	(number_t *) malloc((f->image->height + 8) * sizeof(*c->ypos));
+    if (c->ypos == NULL) {
+	free((void *) c->xpos);
+	return 0;
+    }
+    c->reallocx =
+	(realloc_t *) malloc(sizeof(realloc_t) * (f->image->width + 8));
+    if (c->reallocx == NULL) {
+	free((void *) c->xpos);
+	free((void *) c->ypos);
+	return 0;
+    }
+    c->reallocy =
+	(realloc_t *) malloc(sizeof(realloc_t) * (f->image->height + 8));
+    if (c->reallocy == NULL) {
+	free((void *) c->xpos);
+	free((void *) c->ypos);
+	free((void *) c->reallocx);
+	return 0;
+    }
+    return 1;
+}
+
+static void free_tables(struct filter *f)
+{
+    zoom_context *c = getzcontext(f);
+    if (c->xpos != NULL)
+	free((void *) c->xpos), c->xpos = NULL;
+    if (c->ypos != NULL)
+	free((void *) c->ypos), c->ypos = NULL;
+    if (c->reallocx != NULL)
+	free((void *) c->reallocx), c->reallocx = NULL;
+    if (c->reallocy != NULL)
+	free((void *) c->reallocy), c->reallocy = NULL;
+}
+
+static void free_context(struct filter *f)
+{
+    zoom_context *c;
+    c = getzcontext(f);
+    free_tables(f);
+    free((void *) c);
+    f->data = NULL;
+}
+
+static zoom_context *make_context(void)
+{
+    zoom_context *new_ctxt;
+
+    new_ctxt = (zoom_context *) calloc(1, sizeof(zoom_context));
+    if (new_ctxt == NULL)
+	return NULL;
+    new_ctxt->forversion = -1;
+    new_ctxt->newcalc = 1;
+    new_ctxt->reallocx = NULL;
+    new_ctxt->reallocy = NULL;
+    new_ctxt->xpos = NULL;
+    new_ctxt->ypos = NULL;
+    new_ctxt->uncomplette = 0;
+    return (new_ctxt);
+}
+
+static void startbgmkrealloc(void /*@unused@ */ *data,
+			     struct taskinfo /*@unused@ */ *task,
+			     int /*@unused@ */ r1,
+			     int /*@unused@ */ r2)
+{
+    mkrealloc_table(czoomc.ypos, czoomc.reallocy,
+		    (unsigned int) cimage.height, cfractalc.rs.ni,
+		    cfractalc.rs.mi, cursymetry.ysym, tmpdata1);
+}
+
+static int do_fractal(struct filter *f, int flags, int /*@unused@ */ time)
+{
+    number_t *posptr;
+    int maxres;
+    int size;
+    int rflags = 0;
+    realloc_t *r, *rend;
+
+    f->image->flip(f->image);
+    cfilter = *f;
+    set_fractalc(f->fractalc, f->image);
+
+    if (getzcontext(f)->forversion != f->fractalc->version ||
+	getzcontext(f)->newcalc ||
+	getzcontext(f)->forpversion != f->image->palette->version) {
+	clear_image(f->image);
+	free_tables(f);
+	if (!alloc_tables(f))
+	    return 0;
+	init_tables(f);
+	getzcontext(f)->newcalc = 0;
+	getzcontext(f)->forversion = getfcontext(f)->version;
+	getzcontext(f)->forpversion = f->image->palette->version;
+	czoomc = *getzcontext(f);
+	if (BTRACEOK && !(flags & INTERRUPTIBLE)) {
+	    boundarytraceall(czoomc.xpos, czoomc.ypos);
+	    f->flags &= ~ZOOMMASK;
+	    return CHANGED | (cfilter.interrupt ? UNCOMPLETTE : 0);
+	}
+    } else
+	rflags |= INEXACT;
+
+    czoomc = *getzcontext(f);
+
+    setuncomplette(0);
+    setchanged(0);
+
+    maxres = cimage.width;
+    if (maxres < cimage.height)
+	maxres = cimage.height;
+    size =
+	ALIGN((maxres) * (DSIZE + 1) * (int) sizeof(struct dyn_data)) +
+	2 * ALIGN(maxres * (int) sizeof(struct dyn_data **)) +
+	ALIGN((maxres + 2) * (int) sizeof(int));
+#ifdef HAVE_ALLOCA
+    tmpdata = (unsigned char *) alloca(size);
+#else
+    tmpdata = (unsigned char *) malloc(size);
+#endif
+    if (tmpdata == NULL) {
+	x_error
+	    ("XaoS fatal error:Could not allocate memory for temporary data of size %i. "
+	     "I am unable to handle this problem so please resize to smaller window.",
+	     size);
+	return 0;
+    }
+    if (nthreads != 1) {
+#ifdef HAVE_ALLOCA
+	tmpdata1 = (unsigned char *) alloca(size);
+#else
+	tmpdata1 = (unsigned char *) malloc(size);
+#endif
+	if (tmpdata1 == NULL) {
+	    x_error
+		("XaoS fatal error:Could not allocate memory for temporary data of size %i. "
+		 "I am unable to handle this problem so please resize to smaller window",
+		 size);
+	    return 0;
+	}
+    } else
+	tmpdata1 = tmpdata;
+
+    cfilter.incalculation = 0;
+    cfilter.readyforinterrupt = 0;
+    cfilter.interrupt = 0;
+
+    nsymetrized = 0;
+    cfilter.max = 0;
+    cfilter.pos = 0;
+    cfilter.pass = "Making y realloc table";
+    xth_bgjob(startbgmkrealloc, NULL);
+
+    cfilter.pass = "Making x realloc table";
+    mkrealloc_table(czoomc.xpos, czoomc.reallocx,
+		    (unsigned int) cimage.width, cfractalc.rs.nc,
+		    cfractalc.rs.mc, cursymetry.xsym, tmpdata);
+
+    callwait();
+
+    cfilter.pass = "Moving old points";
+    callwait();
+    preparemoveoldpoints();
+    xth_sync();
+#ifdef _NEVER_
+    {
+	static long long sum2, sum;
+	cli();
+	startagi();
+	sum -= rdtsc();
+	sum2 -= countagi();
+	xth_function(moveoldpoints, NULL, cimage.height);
+	sum += rdtsc();
+	sum2 += countagi();
+	sti();
+	printf("%i %i\n", (int) sum, (int) sum2);
+    }
+#else
+    xth_function(moveoldpoints, NULL, cimage.height);
+#endif
+
+    cfilter.pass = "Starting calculation";
+    callwait();
+    xth_sync();
+    if (flags & INTERRUPTIBLE)
+	calculatenewinterruptible();
+    else {
+	xth_function(calculatenew, NULL, 1);
+	if (cfilter.interrupt) {
+	    getzcontext(f)->uncomplette = 1;
+	}
+	cfilter.pos = 0;
+	cfilter.max = 0;
+	cfilter.pass = "Procesing symetries";
+	callwait();
+	xth_sync();
+	if (nsymetrized) {
+	    xth_function(dosymetry, NULL, cimage.height);
+	    xth_sync();
+	    drivercall(cimage,
+		       xth_function(dosymetry2_8, NULL, cimage.width),
+		       xth_function(dosymetry2_16, NULL, cimage.width),
+		       xth_function(dosymetry2_24, NULL, cimage.width),
+		       xth_function(dosymetry2_32, NULL, cimage.width));
+	    xth_sync();
+	}
+	if (getzcontext(f)->uncomplette) {
+	    fill();
+	}
+    }
+    for (r = czoomc.reallocx, posptr = czoomc.xpos, rend =
+	 czoomc.reallocx + cimage.width; r < rend; r++, posptr++) {
+	*posptr = r->possition;
+    }
+    for (r = czoomc.reallocy, posptr = czoomc.ypos, rend =
+	 czoomc.reallocy + cimage.height; r < rend; r++, posptr++) {
+	*posptr = r->possition;
+    }
+#ifdef STATISTICS
+    STAT(printf("Statistics: frames %i\n"
+		"mkrealloctable: added %i, symetry %i\n"
+		"calculate loop: tocalculate %i avoided %i\n"
+		"calculate:calculated %i inside %i\n"
+		"iters inside:%i iters outside:%i periodicty:%i\n",
+		frames2, nadded2, nsymetry2, tocalculate2, avoided2,
+		ncalculated2, ninside2, niter2, niter1, nperi));
+#endif
+    f->flags &= ~ZOOMMASK;
+    if (getzcontext(f)->uncomplette)
+	rflags |= UNCOMPLETTE, f->flags |= UNCOMPLETTE;
+    if (getzcontext(f)->uncomplette > (cimage.width + cimage.height) / 2)
+	f->flags |= LOWQUALITY;
+    if (getzcontext(f)->changed)
+	rflags |= CHANGED;
+#ifndef HAVE_ALLOCA
+    free(tmpdata);
+    if (nthreads != 1)
+	free(tmpdata1);
+#endif
+    return rflags;
+}
+
+
+static struct filter *getinstance(CONST struct filteraction *a)
+{
+    struct filter *f = createfilter(a);
+    f->data = make_context();
+    f->name = "Zooming engine";
+    return (f);
+}
+
+static void destroyinstance(struct filter *f)
+{
+    free_context(f);
+    free(f);
+}
+
+static int requirement(struct filter *f, struct requirements *r)
+{
+    r->nimages = 2;
+    r->supportedmask =
+	C256 | TRUECOLOR | TRUECOLOR24 | TRUECOLOR16 | LARGEITER |
+	SMALLITER | GRAYSCALE;
+    r->flags = IMAGEDATA | TOUCHIMAGE;
+    return (f->next->action->requirement(f->next, r));
+}
+
+static int initialize(struct filter *f, struct initdata *i)
+{
+#ifdef USE_MULTABLE
+    if (!multable[0]) {
+	int i;
+	mulmid = multable + RANGE * FPMUL;
+	for (i = -RANGE * FPMUL; i < RANGE * FPMUL; i++)
+	    mulmid[i] = i * i;
+    }
+#endif
+    inhermisc(f, i);
+    if (i->image != f->image || datalost(f, i))
+	getzcontext(f)->forversion = -1, f->image = i->image;
+    f->imageversion = i->image->version;
+    return (1);
+}
+
+CONST struct filteraction zoom_filter = {
+    "XaoS's zooming engine",
+    "zoom",
+    0,
+    getinstance,
+    destroyinstance,
+    do_fractal,
+    requirement,
+    initialize,
+    convertupgeneric,
+    convertdowngeneric,
+    NULL,
+};
diff --git a/src/engine/zoomd.c b/src/engine/zoomd.c
new file mode 100644
index 0000000..ef3b965
--- /dev/null
+++ b/src/engine/zoomd.c
@@ -0,0 +1,309 @@
+#ifndef UNSUPPORTED
+
+/*  this two routines implements solid guessing. They are almost same. One
+ *  caluclates lines, second rows.
+ *
+ *  The heruistic is as follows:
+ *
+ *  ---1------6------5-------  (vbuffu)
+ *     |      |      |
+ *  ===7======X======8=======  (vbuff1)
+ *     |      |      |     
+ *  ---2------3------4-------  (vbuffd)
+ *  distdown  rx   distup
+ *
+ *  -- and | means calculated lines. == is current line, names are pointers to
+ *  them. Note that naming is quite confusing, because it is same in lines and
+ *  rows.
+ *
+ *  we do solid guessing as folows: 
+ *  |distl-vbuff1| < range
+ *  |distr-vbuff1| < range
+ *  the distance of distup and distdown is not limited, because we already
+ *  have exact enought guesses 3 and 6
+ *
+ *  points 1 2 3 4 5 6 8 must be the same (point 8 is not yet calculated)
+ *
+ */
+static void calcline(realloc_t * RESTRICT ry) REGISTERS(3);
+REGISTERS(3)
+static void calcline(realloc_t * RESTRICT ry)
+{
+    number_t y;
+    int range = cfractalc.range;
+    realloc_t *RESTRICT rx, *rend, *rend1, *ryl, *ryr;
+    int distl, distr, distup, distdown;
+    cpixel_t *RESTRICT vbuff, *RESTRICT vbuffu, *RESTRICT vbuffd;
+    cpixeldata_t inset = (cpixeldata_t) cpalette.pixels[0];
+    cpixeldata_t c;
+    cppixel_t *vbuff1 =
+	(cpixel_t **) cimage.currlines + (ry - czoomc.reallocy);
+    assert(ry >= czoomc.reallocy);
+    assert(ry < czoomc.reallocy + cimage.height);
+    y = ry->possition;
+    rend = ry - range - 1;
+    if (czoomc.reallocy > rend)
+	rend = czoomc.reallocy;
+    for (ryl = ry - 1; rend <= ryl && ryl->dirty; ryl--);
+    distl = (int) (ryl - ry);
+    rend = ry + range;
+    if (czoomc.reallocy + cimage.height < rend)
+	rend = czoomc.reallocy + cimage.height;
+    for (ryr = ry + 1; rend > ryr && ryr->dirty; ryr++);
+    distr = (int) (ryr - ry);
+    rend = czoomc.reallocy + cimage.height;
+    if (ryr == czoomc.reallocy + cimage.height || ryl < czoomc.reallocy
+	|| ryr->dirty || ryl->dirty) {
+	for (rx = czoomc.reallocx, vbuff = *vbuff1,
+	     rend1 = czoomc.reallocx + cimage.width; rx < rend1; rx++) {
+	    if (!rx->dirty) {
+		STAT(tocalculate++);
+		p_set(vbuff,
+		      (cpixeldata_t) calculate(rx->possition, y,
+					       cfractalc.periodicity));
+#ifdef DRAW
+		vga_setcolor(0xff0000);
+		vga_drawpixel(rx - czoomc.reallocx, ry - czoomc.reallocy);
+#endif
+	    }
+	    p_inc(vbuff, 1);
+	}
+    } else {
+	distup = INT_MAX / 2;
+	distdown = 0;
+	for (rx = czoomc.reallocx,
+	     vbuff = vbuff1[0], vbuffu = vbuff1[distl], vbuffd =
+	     vbuff1[distr], rend1 = czoomc.reallocx + cimage.width;
+	     rx < rend1; rx++) {
+	    assert(rx < czoomc.reallocx + cimage.width);
+	    assert(rx >= czoomc.reallocx);
+	    if (!rx->dirty) {
+		STAT(tocalculate++);
+		if (distdown <= 0) {
+		    for (ryr = rx + 1; ryr < rend1 && ryr->dirty; ryr++);
+		    distdown = (int) (ryr - rx);
+		    if (ryr == rend1)
+			distdown = INT_MAX / 2;
+		}
+		if (distdown < INT_MAX / 4 && distup < INT_MAX / 4 &&
+		    (p_get(vbuffu) == (c = p_get(vbuffd)) &&
+		     c == p_getp(vbuff, -distup) &&
+		     c == p_getp(vbuffu, -distup) &&
+		     c == p_getp(vbuffu, distdown) &&
+		     c == p_getp(vbuffd, distdown) &&
+		     c == p_getp(vbuffd, -distup))) {
+		    p_set(vbuff, c);
+		    STAT(avoided++);
+		} else {
+		    if (cfractalc.periodicity &&
+			distdown < INT_MAX / 4 && distup < INT_MAX / 4 &&
+			(p_get(vbuffu) != inset &&
+			 p_get(vbuffd) != inset &&
+			 p_getp(vbuff, -distup) != inset &&
+			 p_getp(vbuffu, -distup) != inset &&
+			 p_getp(vbuffu, +distdown) != inset &&
+			 p_getp(vbuffd, -distup) != inset &&
+			 p_getp(vbuffd, +distdown) != inset))
+			p_set(vbuff,
+			      (cpixeldata_t) calculate(rx->possition, y,
+						       0));
+		    else
+			p_set(vbuff,
+			      (cpixeldata_t) calculate(rx->possition, y,
+						       cfractalc.
+						       periodicity));
+#ifdef DRAW
+		    vga_setcolor(0xffffff);
+		    vga_drawpixel(rx - czoomc.reallocx,
+				  ry - czoomc.reallocy);
+#endif
+		}
+		distup = 0;
+	    }
+	    p_inc(vbuff, 1);
+	    p_inc(vbuffu, 1);
+	    p_inc(vbuffd, 1);
+	    distdown--;
+	    distup++;
+	}
+    }
+    ry->recalculate = 0;
+    ry->dirty = 0;
+}
+
+static void calccolumn(realloc_t * RESTRICT rx) REGISTERS(3);
+REGISTERS(3)
+static void calccolumn(realloc_t * RESTRICT rx)
+{
+    number_t x;
+    int range = cfractalc.range;
+    realloc_t *RESTRICT ry, *rend, *rend1, *rxl, *rxr;
+    int pos, distl, distr, distup, distdown;
+    cpixeldata_t c;
+    cpixeldata_t inset = (cpixeldata_t) cpalette.pixels[0];
+    cppixel_t *RESTRICT vbuff;
+    pos = (int) (rx - czoomc.reallocx);
+    assert(pos >= 0);
+    assert(pos < cimage.width);
+    rend = rx - range + 1;
+    if (czoomc.reallocx > rend)
+	rend = czoomc.reallocx;
+    for (rxl = rx - 1; rend <= rxl && rxl->dirty; rxl--);
+    distl = (int) (rx - rxl);
+    rend = rx + range;
+    if (czoomc.reallocx + cimage.width < rend)
+	rend = czoomc.reallocx + cimage.width;
+    for (rxr = rx + 1; rxr < rend && rxr->dirty; rxr++);
+    distr = (int) (rxr - rx);
+    x = rx->possition;
+    rend = czoomc.reallocx + cimage.width;
+    if (rxr >= czoomc.reallocx + cimage.width || rxl < czoomc.reallocx
+	|| rxr->dirty || rxl->dirty) {
+	for (ry = czoomc.reallocy, vbuff =
+	     (cppixel_t *) cimage.currlines, rend1 =
+	     czoomc.reallocy + cimage.height; ry < rend1; ry++, vbuff++) {
+	    if (!ry->dirty) {
+		STAT(tocalculate++);
+		p_setp((*vbuff), pos,
+		       (cpixeldata_t) calculate(x, ry->possition,
+						cfractalc.periodicity));
+#ifdef DRAW
+		vga_setcolor(0xff0000);
+		vga_drawpixel(rx - czoomc.reallocx, ry - czoomc.reallocy);
+#endif
+	    }
+	}
+    } else {
+	distl = pos - distl;
+	distr = pos + distr;
+	assert(distl >= 0);
+	assert(distr < cimage.width);
+	distup = INT_MAX / 2;
+	distdown = 0;
+	for (ry = czoomc.reallocy, vbuff =
+	     (cppixel_t *) cimage.currlines, rend1 =
+	     czoomc.reallocy + cimage.height; ry < rend1; ry++) {
+	    /*if (ry->symto == -1) { */
+	    assert(ry < czoomc.reallocy + cimage.height);
+	    if (!ry->dirty) {
+		STAT(tocalculate++);
+		if (distdown <= 0) {
+		    for (rxr = ry + 1; rxr < rend1 && rxr->dirty; rxr++);
+		    distdown = (int) (rxr - ry);
+		    if (rxr == rend1)
+			distdown = INT_MAX / 2;
+		}
+		if (distdown < INT_MAX / 4 && distup < INT_MAX / 4 &&
+		    (p_getp(vbuff[0], distl) ==
+		     (c = p_getp(vbuff[0], distr))
+		     && p_getp(vbuff[-distup], distl) == c
+		     && p_getp(vbuff[-distup], distr) == c
+		     && p_getp(vbuff[-distup], pos) == c
+		     && p_getp(vbuff[distdown], distr) == c
+		     && p_getp(vbuff[distdown], distl) == c)) {
+		    STAT(avoided++);
+		    p_setp(vbuff[0], pos, c);
+		} else {
+		    if (cfractalc.periodicity &&
+			distdown < INT_MAX / 4 && distup < INT_MAX / 4 &&
+			(p_getp(vbuff[0], distl) != inset &&
+			 p_getp(vbuff[0], distr) != inset &&
+			 p_getp(vbuff[distdown], distr) != inset &&
+			 p_getp(vbuff[distdown], distl) != inset &&
+			 p_getp(vbuff[-distup], distl) != inset &&
+			 p_getp(vbuff[-distup], pos) != inset &&
+			 p_getp(vbuff[-distup], distr) != inset))
+			p_setp(vbuff[0], pos,
+			       (cpixeldata_t) calculate(x, ry->possition,
+							0));
+		    else
+			p_setp(vbuff[0], pos,
+			       (cpixeldata_t) calculate(x, ry->possition,
+							cfractalc.
+							periodicity));
+#ifdef DRAW
+		    vga_setcolor(0xffffff);
+		    vga_drawpixel(rx - czoomc.reallocx,
+				  ry - czoomc.reallocy);
+#endif
+		}
+		distup = 0;
+	    }
+	    vbuff++;
+	    distdown--;
+	    distup++;
+	}
+    }
+    rx->recalculate = 0;
+    rx->dirty = 0;
+}
+
+static /*INLINE */ void
+dosymetry2(void /*@unused@ */ *data, struct taskinfo /*@unused@ */ *task,
+	   int r1, int r2)
+{
+    cpixel_t **vbuff = (cpixel_t **) cimage.currlines;
+    realloc_t *rx, *rend;
+    cpixel_t **vend = (cpixel_t **) cimage.currlines + cimage.height;
+    for (rx = czoomc.reallocx + r1, rend = czoomc.reallocx + r2; rx < rend;
+	 rx++) {
+	assert(rx->symto >= 0 || rx->symto == -1);
+	if (rx->symto >= 0) {
+	    assert(rx->symto < cimage.width);
+	    if (!czoomc.reallocx[rx->symto].dirty) {
+		int pos = (int) (rx - czoomc.reallocx);
+		int pos1 = rx->symto;
+		vbuff = (cpixel_t **) cimage.currlines;
+		for (; vbuff < vend; vbuff++)
+		    p_copy(vbuff[0], pos, vbuff[0], pos1);
+		rx->dirty = 0;
+	    }
+	}
+    }
+}
+
+#ifndef USE_i386ASM
+/*
+ * Fill - bitmap depended part.
+ *
+ * This function is called, when calculation was interrupted because of
+ * timeout. It fills uncalculated rows by nearest one
+ *
+ * This function is very time critical in higher resultions I am shooting
+ * for.
+ */
+#ifndef __GNUC__
+#undef bpp1
+#endif
+#ifndef __i386__
+#undef bpp1
+#endif
+#undef bpp1
+
+static INLINE void fillline(int line)
+{
+    register unsigned char *RESTRICT vbuff = cimage.currlines[line];
+    CONST struct filltable *RESTRICT table = (struct filltable *) tmpdata;
+    while (table->length) {
+	register cpixeldata_t s =
+	    p_get((cpixel_t *) (vbuff + table->from));
+	register cpixel_t *vcurr = (cpixel_t *) (vbuff + table->to);
+#ifdef bpp1
+	memset(vcurr, s, table->length);
+#else
+	register cpixel_t *vend = (cpixel_t *) (vbuff + table->end);
+	while (vcurr < vend) {
+	    p_set(vcurr, s);
+	    p_inc(vcurr, 1);
+	}
+#endif
+	table++;
+    }
+}
+#endif
+#endif
+#undef dosymetry2
+#undef calcline
+#undef calccolumn
+#undef fillline
+#undef rend
--
cgit v0.9.1