Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/engine/dither.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/dither.c')
-rw-r--r--src/engine/dither.c1200
1 files changed, 1200 insertions, 0 deletions
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