diff options
Diffstat (limited to 'src/engine/dither.c')
-rw-r--r-- | src/engine/dither.c | 1200 |
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 |