diff options
Diffstat (limited to 'src/engine')
35 files changed, 12439 insertions, 0 deletions
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 <config.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> /*for NULL */ +#include <math.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <xthread.h> +#include <filter.h> + +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 <c256.h> +#define do_3d do_3d8 +#define convert_3d convert_3d8 +#define convertup_3d convertup_3d8 +#include "3dd.c" + +#include <truecolor.h> +#define do_3d do_3d32 +#define convert_3d convert_3d32 +#define convertup_3d convertup_3d32 +#include "3dd.c" + +#include <true24.h> +#define do_3d do_3d24 +#define convert_3d convert_3d24 +#define convertup_3d convertup_3d24 +#include "3dd.c" + +#include <hicolor.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef __cplusplus +#include <math.h> +#endif +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <string.h> +#include <config.h> +#include <stdio.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <xerror.h> +#include <filter.h> +#include <fractal.h> +#include <xthread.h> +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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <string.h> +#include <math.h> +#include <stdio.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <fractal.h> +#include <xthread.h> +#include <xerror.h> +#include <archaccel.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <filter.h> +#include <fractal.h> +#include <xthread.h> +/* + * 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 <alloca.h> +#endif +#include <archaccel.h> + +#include <filter.h> +#include <btrace.h> +#include <plane.h> +#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<<PAGESHIFT) +#define MAXPAGES 200 /*Well limit is about 6MB of stack..Hope it will never owerflow */ +#define MAXSIZE (MAXPAGES*PAGESIZE-1) +struct stack { + int color; + short x, y; + char direction; +}; +static int npages[MAXTHREADS]; +static struct stack *pages[MAXPAGES]; +static struct stack **starts[MAXTHREADS]; +static int sizes[MAXTHREADS]; +static int maxsize, maxsize2; +static CONST char dirrections[][2] = { + {0, -1}, + {1, 0}, + {0, 1}, + {-1, 0}, +}; + +#define addstack(sx,sy,d,c,periodicity) { \ + int page; \ + int nstack=(((sy)-ystart)*nthreads)/(yend-ystart+1); \ + struct stack *ptr; \ + calculated[sx+sy*CALCWIDTH]|=1<<d; \ + xth_lock(0); \ + if(size<maxsize2) {\ + while(sizes[nstack]>=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<<d; \ + if(size<maxsize2) {\ + while(sizes[nstack]>=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 <c256.h> +#define tracecolor tracecolor8 +#define tracepoint tracepoint8 +#define dosymetries dosymetries8 +#define queue queue8 +#define bfill bfill8 +#include "btraced.c" +#include <hicolor.h> +#define tracecolor tracecolor16 +#define tracepoint tracepoint16 +#define dosymetries dosymetries16 +#define queue queue16 +#define bfill bfill16 +#include "btraced.c" +#include <true24.h> +#define tracecolor tracecolor24 +#define tracepoint tracepoint24 +#define dosymetries dosymetries24 +#define queue queue24 +#define bfill bfill24 +#include "btraced.c" +#include <truecolor.h> +#define tracecolor tracecolor32 +#define tracepoint tracepoint32 +#define dosymetries dosymetries32 +#define queue queue32 +#define bfill bfill32 +#include "btraced.c" + +#ifdef HAVE_GETTEXT +#include <libintl.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> +#include <string.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <fconfig.h> +#include <filter.h> +#include <xerror.h> +#include <fractal.h> +#include <xthread.h> +#include <archaccel.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> /*for NULL */ +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <xthread.h> +#include <filter.h> + +#define spixel_t pixel8_t +#include <c256.h> +#define do_edge do_edge8 +#include "edged.c" + +#undef spixel_t +#define spixel_t pixel16_t +#include <truecolor.h> +#define do_edge do_edge32 +#include "edged.c" + +#include <true24.h> +#define do_edge do_edge24 +#include "edged.c" + +#include <hicolor.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> /*for NULL */ +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <xthread.h> +#include <filter.h> + +#define spixel_t pixel8_t +#include <c256.h> +#define do_edge do_edge8 +#include "edge2d.c" + +#undef spixel_t +#define spixel_t pixel16_t +#include <truecolor.h> +#define do_edge do_edge32 +#include "edge2d.c" + +#include <true24.h> +#define do_edge do_edge24 +#include "edge2d.c" + +#include <hicolor.h> +#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 <config.h> +#ifndef _plan9_ +#ifdef NO_MALLOC_H +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <stdio.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <fractal.h> +#include <xthread.h> +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 <u.h> +#include <libc.h> +#include <stdio.h> +#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 <aconfig.h> +#endif + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <float.h> +#ifdef __EMX__ +#include <sys/cdefs.h> +#endif +#include <stdio.h> +#endif /*plan9 */ +#include <archaccel.h> +#include <config.h> +#include <complex.h> +#include <filter.h> +#include <fractal.h> +#include "julia.h" +#include <ui_helper.h> +#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)<cfractalc.bailout) +#define greater_then_1Em6(n) ((n)>1E-6) +#define abs_less_than(x,y) (myabs(x)<y) +#define greater_than(x,y) ((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) +#define FORMULA \ + zre=2*zre;zim=2*zim; \ + if((pim*zre-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) +#define FORMULA \ + zre=1.6180339*zre;zim=1.6180339*zim; \ + if((pim*zre-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<pre/3)||(zre>2*pre/3)|| \ + (zim<pim/3)||(zim>2*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 <aconfig.h> +#include <string.h> +#include <config.h> +#include <fconfig.h> +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#else +#include <stdio.h> +#ifndef _MAC +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#endif +#ifndef _plan9_ +#include <limits.h> +#include <assert.h> +#include <math.h> +#endif +#endif +#ifdef __EMX__ +#include <float.h> +#include <sys/cdefs.h> +#endif +#include <filter.h> +#include <complex.h> +#include <plane.h> +#include "../include/timers.h" +#ifdef __GNUC__ +#ifdef __i386__ +#ifndef PC_64 +#include <i386/ctrl87.h> +#endif +#endif +#endif +#ifdef __alpha__ +#ifdef __linux__ +#include <asm/fpu.h> +#endif +#endif +#ifndef M_PI +#define M_PI 3.1415 +#endif +#include <xerror.h> + +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 <config.h> + +#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 <rlk@tiac.net> + * 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 <sys/types.h> + +#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 <config.h> +#ifndef _plan9_ +#ifdef NO_MALLOC_H +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <stdio.h> /*for NULL */ +#include <string.h> /*for memcpy */ +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <config.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <filter.h> +#include <xthread.h> +#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 <true24.h> +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 <u.h> +#include <stdio.h> +#include <libc.h> +#else +#include <math.h> +#include <string.h> +#include <config.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#endif +#include <filter.h> +#include "julia.h" +#include <config.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <filter.h> +#include <archaccel.h> + + +/*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 <config.h> +#ifndef _plan9_ +#ifdef NO_MALLOC_H +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <stdio.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <fractal.h> +#include <xthread.h> +struct palettedata { + struct palette *palette; + int active; + unsigned int table[256]; +}; +#include <c256.h> +#define cpalette palette8 +#include "paletted.c" + +#include <truecolor.h> +#define cpalette palette32 +#include "paletted.c" + +#include <true24.h> +#define cpalette palette24 +#include "paletted.c" + +#include <hicolor.h> +#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 <float.h> +#include <sys/cdefs.h> +#endif +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#ifndef NULL +#define NULL (void *)0 +#endif +#else +#include <stdio.h> +#include <aconfig.h> +#include <math.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#include <config.h> +#endif +#include <fconfig.h> +#include <plane.h> +#include <complex.h> +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 <config.h> +#ifndef _plan9_ +#include <string.h> +#include <limits.h> +#include <archaccel.h> +#ifndef __cplusplus +#include <math.h> +#endif +#ifdef NO_MALLOC_H +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#define SLARGEITER +#include <xthread.h> +#include <filter.h> + +struct rotatedata { + number_t angle; + number_t x1, y1, x2, y2, xx1, yy1, xx2, yy2; +}; + +#include <c256.h> +#define do_rotate do_rotate8 +#include "rotated.c" + +#include <truecolor.h> +#define do_rotate do_rotate32 +#include "rotated.c" + +#include <true24.h> +#define do_rotate do_rotate24 +#include "rotated.c" + +#include <hicolor.h> +#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 <config.h> +#ifndef _plan9_ +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <config.h> +#include <limits.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <xthread.h> + +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 <c256.h> +#define do_starfield do_starfield8 +#include "stard.c" +#include <hicolor.h> +#define do_starfield do_starfield16 +#include "stard.c" +#include <true24.h> +#define do_starfield do_starfield24 +#include "stard.c" +#include <truecolor.h> +#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 <config.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#include <stdlib.h> +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <xthread.h> +#include <filter.h> + +#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 <c256.h> +#define do_stereogram do_stereogram8 +#include "stereod.c" + +#include <hicolor.h> +#define do_stereogram do_stereogram16 +#include "stereod.c" + +#include <true24.h> +#define do_stereogram do_stereogram24 +#include "stereod.c" + +#include <truecolor.h> +#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 <config.h> +#ifdef NO_MALLOC_H +#include <stdlib.h> +#else +#include <malloc.h> +#endif +#include <stdio.h> /*for NULL */ +#include <string.h> /*for memcpy */ +#else +#include <u.h> +#include <libc.h> +#include <stdio.h> +#endif +#include <filter.h> +#include <zoom.h> +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 <config.h> +#include <fconfig.h> +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#else +#include <stdlib.h> +#include <stdio.h> +#ifndef _MAC +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#endif +#ifdef __EMX__ +#include <float.h> +#include <sys/cdefs.h> +#endif +#include <aconfig.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#include <math.h> +#include <string.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#ifndef _plan9_ +/*#undef NDEBUG */ +#include <assert.h> +#endif +#endif +#define SLARGEITER +#include <filter.h> +#include <zoom.h> +#include <archaccel.h> +#include <complex.h> /*for myabs */ +#include <plane.h> +#include <btrace.h> +#include <xthread.h> +#include <xerror.h> +#include "calculate.h" /*an inlined calulate function */ + +#ifdef HAVE_GETTEXT +#include <libintl.h> +#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 <c256.h> +#define fillline fillline_8 +#define dosymetry2 dosymetry2_8 +#define calcline calcline_8 +#define calccolumn calccolumn_8 +#include "zoomd.c" + +#include <truecolor.h> +#define fillline fillline_32 +#define dosymetry2 dosymetry2_32 +#define calcline calcline_32 +#define calccolumn calccolumn_32 +#include "zoomd.c" + +#include <true24.h> +#define fillline fillline_24 +#define dosymetry2 dosymetry2_24 +#define calcline calcline_24 +#define calccolumn calccolumn_24 +#include "zoomd.c" + +#include <hicolor.h> +#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)<<DSIZES)+(((i)&(DSIZEHMASK))))) +#define getbest(i) (dyndata+((size)<<DSIZES)+(i)) +#define nosetadd ((size*2)<<DSIZES) +#ifndef DEBUG +#define CHECKPOS(pos) +#else +#define CHECKPOS(pos) (assert((pos)>=dyndata),assert((pos)<dyndata+(size)+((size)<<DSIZES))) +#endif + +#ifdef __POWERPC__ +# undef USE_MULTABLE +#else +# define USE_MULTABLE 1 +#endif + +#ifdef USE_MULTABLE +#define PRICE(i,i1) mulmid[(i)-(i1)] +#else +#define PRICE(i,i1) (((i)-(i1)) * ((i)-(i1))) +#endif +#define NEWPRICE (FPMUL*FPMUL*(RANGE)*(RANGE)) + +#define NOSETMASK ((unsigned int)0x80000000) +#define END NULL +#define MAXPRICE INT_MAX +/*static int dynsize = (int)sizeof (struct dyn_data);*/ +#ifndef INT_MIN +#define INT_MIN (- INT_MAX - 1) +#endif +#define IRANGE FPMUL*RANGE + +#ifdef USE_MULTABLE +static int multable[RANGE * FPMUL * 2]; +static int *mulmid; +#endif + +/*Functions looks trought rows/columns marked for calculation and tries to use + *some symetrical one instead + */ + +/*FIXME should be threaded...but thread overhead should take more work than + *do it in one, since it is quite simple and executes just in case fractal + *on the screen is symetrical and it is quite rare case...who knows + */ +static void + /*INLINE */ preparesymetries(register realloc_t * realloc, CONST int size, + register + int symi, + number_t + sym, + number_t + step) +{ + register int i; + register int istart = 0; + number_t fy, ftmp; + realloc_t *r = realloc, *reallocs; + + sym *= 2; + i = 2 * symi - size; + if (i < 0) + i = 0; + realloc += i; + + for (; i <= symi; i++, realloc++) { /*makes symetries */ + int j, min = 0; + number_t dist = NUMBER_BIG, tmp1; + + if (realloc->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 |