Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/3d.c240
-rw-r--r--src/engine/3dd.c200
-rw-r--r--src/engine/Makefile.in70
-rw-r--r--src/engine/anti.c358
-rw-r--r--src/engine/blur.c393
-rw-r--r--src/engine/btrace.c596
-rw-r--r--src/engine/btraced.c466
-rw-r--r--src/engine/calculate.h37
-rw-r--r--src/engine/dither.c1200
-rw-r--r--src/engine/docalc.c790
-rw-r--r--src/engine/edge.c113
-rw-r--r--src/engine/edge2.c113
-rw-r--r--src/engine/edge2d.c53
-rw-r--r--src/engine/edged.c66
-rw-r--r--src/engine/emboss.c266
-rw-r--r--src/engine/engine.pri35
-rw-r--r--src/engine/formulas.c3038
-rw-r--r--src/engine/fractal.c471
-rw-r--r--src/engine/i386.c187
-rw-r--r--src/engine/interlace.c134
-rw-r--r--src/engine/itersmall.c171
-rw-r--r--src/engine/julia.c120
-rw-r--r--src/engine/julia.h18
-rw-r--r--src/engine/paletted.c22
-rw-r--r--src/engine/palettef.c165
-rw-r--r--src/engine/plane.c144
-rw-r--r--src/engine/rotate.c200
-rw-r--r--src/engine/rotated.c56
-rw-r--r--src/engine/star.c135
-rw-r--r--src/engine/stard.c31
-rw-r--r--src/engine/stereod.c51
-rw-r--r--src/engine/stereogram.c193
-rw-r--r--src/engine/subwindow.c236
-rw-r--r--src/engine/zoom.c1762
-rw-r--r--src/engine/zoomd.c309
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