diff options
Diffstat (limited to 'src/filter/palette.c')
-rw-r--r-- | src/filter/palette.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/src/filter/palette.c b/src/filter/palette.c new file mode 100644 index 0000000..6eae282 --- /dev/null +++ b/src/filter/palette.c @@ -0,0 +1,1097 @@ +#ifdef _plan9_ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#else +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <fconfig.h> +#include <config.h> +#include <assert.h> +#include <stdio.h> +#ifndef NO_MALLOC_H +#include <malloc.h> +#endif +#include <limits.h> +#endif +#include <fconfig.h> +#include <filter.h> +#include <misc-f.h> +#include <xerror.h> + +#define nprecells (context->type & (LARGEITER|SMALLITER|TRUECOLOR|TRUECOLOR16|TRUECOLOR24)?0:(context)->ncells) +#define PREALLOCATED(palette) ((palette)->type & (LARGEITER|SMALLITER|TRUECOLOR|TRUECOLOR16|TRUECOLOR24)?0:(palette)->npreallocated) +/*emulate allocation routines using setpalette */ +unsigned col_diff[3][512]; +static struct palette *context; +static int maxentries; +static int needupdate; +static void +genertruecolorinfo(struct truec *t, unsigned int r, unsigned int g, + unsigned int b) +{ + int n; + + for (n = 0; !((r >> n) & 1); n++); + t->rshift = n; + for (; ((r >> n) & 1); n++); + t->rprec = 8 - (n - t->rshift); + t->rmask = r; + + for (n = 0; !((g >> n) & 1); n++); + t->gshift = n; + for (; ((g >> n) & 1); n++); + t->gprec = 8 - (n - t->gshift); + t->gmask = g; + + for (n = 0; !((b >> n) & 1); n++); + t->bshift = n; + for (; ((b >> n) & 1); n++); + t->bprec = 8 - (n - t->bshift); + t->bmask = b; + + t->allmask = r | g | b; + if ((r & b) || (r & g) || (b & g)) { + x_fatalerror("Internal error:Invalid color masks 1 %x %x %x!\n", r, + g, b); + } + if ((r < g && g < b) || (b < g && g < r)) { + t->mask1 = r | b; + t->mask2 = g; + } else if ((g < r && r < b) || (b < r && r < g)) { + t->mask1 = g | b; + t->mask2 = r; + } else if ((g < b && b < r) || (r < b && b < g)) { + t->mask1 = g | r; + t->mask2 = b; + } + t->byteexact = 0; + t->missingbyte = -1; + if (!(t->rshift % 8) && + !(t->gshift % 8) && + !(t->bshift % 8) && !t->rprec && !t->gprec && !t->bprec) { + t->byteexact = 1; + { + unsigned char ch[4]; + *(unsigned int *) ch = t->allmask; + if (!ch[0]) + t->missingbyte = 0; + if (!ch[1]) + t->missingbyte = 1; + if (!ch[2]) + t->missingbyte = 2; + if (!ch[3]) + t->missingbyte = 3; + } + } +#ifdef DEBUG + printf("Image:\n"); + printf("rshift:%i gshift:%i bshift:%i\n", t->rshift, t->gshift, + t->bshift); + printf("rprec:%i gprec:%i bprec:%i\n", t->rprec, t->gprec, t->bprec); + printf("rmask:%x gmask:%x bmask:%x\n", t->rmask, t->gmask, t->bmask); + printf("mask1:%x mask2:%x allmask:%x\n", t->mask1, t->mask2, + t->allmask); + printf("byteexact:%x missingbyte:%i\n", t->byteexact, t->missingbyte); +#endif +} + +void bestfit_init(void) +{ + int i; + + for (i = 1; i < 256; i++) { + int k = i * i; + col_diff[0][i] = col_diff[0][512 - i] = k * (59 * 59) / 256; + col_diff[1][i] = col_diff[1][512 - i] = k * (30 * 30) / 256; + col_diff[2][i] = col_diff[2][512 - i] = k * (11 * 11) / 256; + } +} + +static int +allocgenerictruecolor(struct palette *palette, int init, int r, int g, + int b) +{ + unsigned int n; + switch (palette->type) { + case LARGEITER: + case SMALLITER: +#ifdef _UNDEFINED_ + if (init) + n = 0; + else + n = palette->size; +#endif + return 1; + case TRUECOLOR: + case TRUECOLOR16: + case TRUECOLOR24: + default: + n = ((r >> palette->info.truec.rprec) << palette->info.truec. + rshift) | ((g >> palette->info.truec.gprec) << palette->info. + truec.gshift) | ((b >> palette->info.truec. + bprec) << palette->info.truec. + bshift); + break; + } + if (init) + palette->size = 0; + else if (palette->size >= palette->maxentries) + return -1; + palette->pixels[palette->size] = n; + palette->size++; + return palette->size; +} + +static int +allocgeneric(struct palette *palette, int init, int r, int g, int b) +{ + int start = palette->npreallocated + palette->start; + if (init) + palette->size = 0; + else if (palette->size >= palette->end - start) + return -1; + palette->pixels[palette->size] = palette->size + start; + palette->rgb[palette->size + start][0] = r; + palette->rgb[palette->size + start][1] = g; + palette->rgb[palette->size + start][2] = b; + palette->size++; + return (palette->size - 1); +} + +int fixedalloccolor(struct palette *palette, int init, int r, int g, int b) +{ + int i, coldif, lowest, bestfit; + if (init) + palette->size = 0; + else if (palette->size >= palette->maxentries) + return -1; + lowest = INT_MAX; + bestfit = 1; + if (palette->type == FIXEDCOLOR || (palette->type & BITMAPS)) { + for (i = palette->start; i < palette->end; i++) { + coldif = col_diff[0][(g - palette->rgb[i][1]) & 0x1ff]; + if (coldif < lowest) { + coldif += col_diff[1][(r - palette->rgb[i][0]) & 0x1ff]; + if (coldif < lowest) { + coldif += + col_diff[2][(b - palette->rgb[i][2]) & 0x1ff]; + if (coldif < lowest) { + bestfit = i; + if (!coldif) + break; + lowest = coldif; + } + } + } + } + } else { + bestfit = + (r * 30 + g * 59 + b * 11) * (palette->end - + palette->start) / 256 / 100 + + palette->start; + } + palette->pixels[palette->size] = bestfit; + palette->size++; + return (palette->size - 1); +} + +static void +setcolorgeneric(struct palette *palette, int start, int end, rgb_t * rgb) +{ +} + +static void allocfinishedgeneric(struct palette *palette) +{ + palette->setpalette(palette, palette->start, + palette->size + palette->start + + palette->npreallocated, + palette->rgb + palette->start); +} + +static void cycle_entries(struct palette *c, int direction) +{ + int i; + int i1, i2, i3; + rgb_t *co; + if (direction > 0) + direction %= c->size - 1; + else + direction = -((-direction) % (c->size - 1)); + if (!direction) + return; + co = (rgb_t *) malloc(c->end * sizeof(rgb_t)); + memcpy(co, c->rgb, sizeof(*co) * c->end); + i3 = (c->size - 1 + direction) % (c->size - 1) + 1; + for (i = 1; i < c->size; i++) { + i1 = c->pixels[i]; + i2 = c->pixels[i3]; + c->rgb[i1][0] = co[i2][0]; + c->rgb[i1][1] = co[i2][1]; + c->rgb[i1][2] = co[i2][2]; + i3++; + if (i3 >= c->size) + i3 = 1; + } + free(co); +} + +static void cyclecolorsgeneric(struct palette *pal, int direction) +{ + cycle_entries(pal, direction); + pal->setpalette(pal, pal->pixels[0], pal->size + pal->pixels[0], + pal->rgb + pal->pixels[0]); +} + +#define TRUECOLORPALETTE 65536 +struct palette *createpalette(int start, int end, int type, int flags, + int maxentries, + int (*alloccolor) (struct palette * pal, + int init, int r, int g, + int b), + void (*setcolor) (struct palette * pal, + int start, int end, + rgb_t * rgb), + void (*allocfinished) (struct palette * pal), + void (*cyclecolors) (struct palette * pal, + int direction), + union paletteinfo *info) +{ + static int versioncount; + struct palette *palette = + (struct palette *) calloc(1, sizeof(struct palette)); + + if (col_diff[0][1] == 0) + bestfit_init(); + palette->ncells = 0; + palette->index = NULL; + palette->size = 0; + palette->rgb = NULL; + if (palette == NULL) + return NULL; + + switch (type) { + case LBITMAP: + case MBITMAP: + case LIBITMAP: + case MIBITMAP: + end = 2; + start = 0; + maxentries = 256; + palette->rgb = (rgb_t *) calloc(end, sizeof(*palette->rgb)); + if (palette->rgb == NULL) { + free(palette); + return NULL; + } + if (type & (LIBITMAP | MIBITMAP)) { + palette->rgb[0][0] = 255; + palette->rgb[0][1] = 255; + palette->rgb[0][2] = 255; + palette->rgb[1][0] = 0; + palette->rgb[1][1] = 0; + palette->rgb[1][2] = 0; + } else { + palette->rgb[0][0] = 0; + palette->rgb[0][1] = 0; + palette->rgb[0][2] = 0; + palette->rgb[1][0] = 255; + palette->rgb[1][1] = 255; + palette->rgb[1][2] = 255; + } + palette->maxentries = maxentries; + palette->alloccolor = fixedalloccolor; + palette->setpalette = NULL; + palette->allocfinished = NULL; + palette->cyclecolors = NULL; + break; + case FIXEDCOLOR: + if (!end) + end = 256; + if (!maxentries) + maxentries = 256; + palette->rgb = (rgb_t *) calloc(end, sizeof(*palette->rgb)); + if (palette->rgb == NULL) { + free(palette); + return NULL; + } + palette->maxentries = maxentries; + palette->alloccolor = fixedalloccolor; + palette->setpalette = NULL; + palette->allocfinished = NULL; + palette->cyclecolors = NULL; + break; + case GRAYSCALE: + if (!end) + end = 256; + if (!maxentries) + maxentries = end - start; + palette->maxentries = 65536; + palette->alloccolor = fixedalloccolor; + palette->setpalette = NULL; + palette->allocfinished = NULL; + palette->cyclecolors = NULL; + palette->size = end - start; + break; + case C256: + + if (!end) + end = 256; + if (!maxentries) + maxentries = end - start; + if (cyclecolors == NULL && setcolor != NULL) + cyclecolors = cyclecolorsgeneric; + + if (alloccolor == NULL) { + alloccolor = allocgeneric, allocfinished = + allocfinishedgeneric; + if (setcolor == NULL && type == C256) /*non hardware palette */ + setcolor = setcolorgeneric, cyclecolors = + cyclecolorsgeneric; + } + palette->rgb = (rgb_t *) calloc(end, sizeof(*palette->rgb)); + + if (palette->rgb == NULL) { + free(palette); + return NULL; + } + + palette->maxentries = maxentries; + palette->alloccolor = alloccolor; + palette->setpalette = setcolor; + palette->allocfinished = allocfinished; + palette->cyclecolors = cyclecolors; + + break; + default: + end = TRUECOLORPALETTE; + start = 0; + if (type == SMALLITER) + end = 256; + start = 0; + palette->maxentries = end; + palette->alloccolor = allocgenerictruecolor; + palette->cyclecolors = NULL; + palette->setpalette = NULL; + palette->allocfinished = NULL; + } + { + int ee = palette->maxentries; + /*if(end>palette->maxentries) ee=end; */ + if (ee < 256) + palette->pixels = + (unsigned int *) calloc(256, sizeof(*palette->pixels)); + else + palette->pixels = + (unsigned int *) calloc(ee, sizeof(*palette->pixels)); + } + if (palette->pixels == NULL) { + free(palette); + return NULL; + } + if (type & (LARGEITER | SMALLITER)) { + int i; + palette->size = end; + palette->flags |= DONOTCHANGE; + for (i = 0; i < end; i++) + palette->pixels[i] = i; + } + palette->start = start; + palette->end = end; + palette->type = type; + palette->flags |= flags; + palette->version = (versioncount += 65536); + if (type == FIXEDCOLOR) { + int i; + if (setcolor != NULL) + setcolor(palette, start, end, palette->rgb); + for (i = 0; i < end - start; i++) + palette->pixels[i] = i + start; + } + if (type == GRAYSCALE) { + int i; + for (i = palette->start; i < end - start; i++) + palette->pixels[i] = i + start; + } + if (info != NULL + && (type == TRUECOLOR || type == TRUECOLOR24 + || type == TRUECOLOR16)) { + genertruecolorinfo(&palette->info.truec, info->truec.rmask, + info->truec.gmask, info->truec.bmask); + } else { + if (type == TRUECOLOR) + genertruecolorinfo(&palette->info.truec, 255 << 16, 255 << 8, + 255); + if (type == TRUECOLOR24) + genertruecolorinfo(&palette->info.truec, 255 << 16, 255 << 8, + 255); + if (type == TRUECOLOR16) + genertruecolorinfo(&palette->info.truec, (255 >> 3) << 11, + (255 >> 2) << 5, (255 >> 3)); + } + return (palette); +} + +void destroypalette(struct palette *palette) +{ + free(palette->pixels); + if (palette->rgb != NULL) + free(palette->rgb); + if (palette->index != NULL) + free(palette->index); + free(palette); +} + +#define MYMIN(x,y) ((x)<(y)?(x):(y)) +struct palette *clonepalette(struct palette *palette) +{ + struct palette *pal = + createpalette(palette->start, palette->end, palette->type, + palette->flags, palette->maxentries, + /*palette->alloccolor, palette->setpalette, palette->allocfinished, palette->cyclecolors */ + NULL, NULL, NULL, NULL, &palette->info); + memcpy(pal->pixels, palette->pixels, + sizeof(*pal->pixels) * MYMIN(palette->end, pal->end)); + if (pal->rgb != NULL) { + memcpy(pal->rgb, palette->rgb, + sizeof(*pal->rgb) * MYMIN(palette->end, pal->end)); + } + pal->size = palette->size; + return (pal); +} + +void preallocpalette(struct palette *pal) +{ + int i; + int p; + if (pal->index != NULL) + free(pal->index), pal->index = NULL; + pal->npreallocated = 0; + if (!pal->ncells) + return; + pal->index = (unsigned int *) malloc(sizeof(int) * (pal->ncells + 1)); + for (i = 0; i < pal->ncells; i++) { + if (!i) + p = pal->pixels[0]; + else + p = pal->pixels[pal->size]; + pal->alloccolor(pal, i == 0, pal->prergb[i][0], pal->prergb[i][1], + pal->prergb[i][2]); + if (pal->size) { + pal->index[i] = pal->pixels[pal->size - 1]; + pal->pixels[pal->size - 1] = p; + } + } + pal->npreallocated = pal->size; + pal->size = 0; + needupdate = 0; +} + +void restorepalette(struct palette *dest, struct palette *src) +{ + int i; + preallocpalette(dest); + for (i = 0; i < src->size; i++) { + int r = 0, g = 0, b = 0; + switch (src->type) { + case SMALLITER: + r = g = b = i; + break; + case LARGEITER: + r = g = b = i / 256; + break; + case GRAYSCALE: + r = g = b = src->pixels[i]; + break; + case C256: + case FIXEDCOLOR: + case MBITMAP: + case LBITMAP: + case MIBITMAP: + case LIBITMAP: + r = src->rgb[src->pixels[i]][0]; + g = src->rgb[src->pixels[i]][1]; + b = src->rgb[src->pixels[i]][2]; + break; + case TRUECOLOR: + case TRUECOLOR16: + case TRUECOLOR24: + r = (((src->pixels[i] & src->info.truec.rmask) >> src-> + info.truec.rshift)) << src->info.truec.rprec; + g = (((src->pixels[i] & src->info.truec.gmask) >> src-> + info.truec.gshift)) << src->info.truec.gprec; + b = (((src->pixels[i] & src->info.truec.bmask) >> src-> + info.truec.bshift)) << src->info.truec.bprec; + break; + } + if (dest->size >= dest->maxentries - PREALLOCATED(dest)) + break; + if (dest-> + alloccolor(dest, (i + dest->npreallocated) == 0, r, g, + b) == -1) + break; + } + if (!(dest->flags & FINISHLATER)) { + if (dest->allocfinished != NULL) + dest->allocfinished(dest); + } else + dest->flags |= UNFINISHED; + dest->version++; +} + +/*Generation code for various palettes */ + + +#define DEFNSEGMENTS (255/8) +#define MAXNSEGMENTS (4096) +#define NSEGMENTS ((255/segmentsize)) +static int segmentsize; + + +static unsigned char colors[MAXNSEGMENTS][3]; +static CONST unsigned char colors1[DEFNSEGMENTS][3] = { + /*{8, 14, 32}, */ + {0, 0, 0}, + {120, 119, 238}, + {24, 7, 25}, + {197, 66, 28}, + {29, 18, 11}, + {135, 46, 71}, + {24, 27, 13}, + {241, 230, 128}, + {17, 31, 24}, + {240, 162, 139}, + {11, 4, 30}, + {106, 87, 189}, + {29, 21, 14}, + {12, 140, 118}, + {10, 6, 29}, + {50, 144, 77}, + {22, 0, 24}, + {148, 188, 243}, + {4, 32, 7}, + {231, 146, 14}, + {10, 13, 20}, + {184, 147, 68}, + {13, 28, 3}, + {169, 248, 152}, + {4, 0, 34}, + {62, 83, 48}, + {7, 21, 22}, + {152, 97, 184}, + {8, 3, 12}, + {247, 92, 235}, + {31, 32, 16} +}; + +REGISTERS(3) +static int allocate(int r, int g, int b, int init) +{ + unsigned int n; + if (init) + preallocpalette(context); + n = context->pixels[(init ? 0 : context->size) /*+ context->start */ ]; + if (!init && context->size == maxentries) + return 0; + if ((context->alloccolor(context, init + && !context->npreallocated, (int) r, (int) g, + (int) b)) == -1) { + return 0; + } + if (context->pixels[context->size - 1 /*+ context->start */ ] != n) { + needupdate = 1; + } + return (1); +} + +static int mksmooth(int nsegments, int setsegments) +{ + int i, y; + float r, g, b, rs, gs, bs; + int segmentsize1 = segmentsize; + + for (i = 0; i < setsegments; i++) { + if (i == setsegments - 1 && !(context->flags & UNKNOWNENTRIES)) { + segmentsize1 = maxentries - context->size - 2; + } + r = colors[i % nsegments][0]; + g = colors[i % nsegments][1]; + b = colors[i % nsegments][2]; + rs = ((int) colors[(i + 1) % setsegments % nsegments][0] - + r) / (unsigned int) segmentsize1; + gs = ((int) colors[(i + 1) % setsegments % nsegments][1] - + g) / (unsigned int) segmentsize1; + bs = ((int) colors[(i + 1) % setsegments % nsegments][2] - + b) / (unsigned int) segmentsize1; + for (y = 0; y < segmentsize1; y++) { + if (!allocate((int) r, (int) g, (int) b, i == 0 && y == 0)) { + if (!i) + context->size = 2; + context->size = i * segmentsize; + return 0; + } + r += rs; + g += gs; + b += bs; + } + } + if (context->flags & UNKNOWNENTRIES) + context->size = i * segmentsize; + return 1; +} + +static INLINE void +hsv_to_rgb(int h, int s, int v, + unsigned char *red, unsigned char *green, unsigned char *blue) +{ + int hue; + int f, p, q, t; + h += 256; + h %= 256; + + 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 void randomize_segments3(int whitemode, int nsegments) +{ + int i = 0; + int h, s, v; + + for (i = 0; i < nsegments; i++) { + if (!(i % 3)) { + if (i % 6) + colors[i][0] = 255, colors[i][1] = 255, colors[i][2] = 255; + else + colors[i][0] = 0, colors[i][1] = 0, colors[i][2] = 0; + } else { + s = (int) XaoS_random() % 256; + h = (int) XaoS_random() % (128 - 32); + v = (int) XaoS_random() % 128; + if (((i) % 6 > 3) ^ ((i) % 3 == 1)) + /*if(((i)%3==1)) */ + h += 42 + 16; + else + h += 42 + 128 + 16, v += 128 + 64; + hsv_to_rgb(h, s, v, colors[i], colors[i] + 1, colors[i] + 2); + } + } + colors[i - 1][0] = colors[0][0]; + colors[i - 1][1] = colors[0][1]; + colors[i - 1][2] = colors[0][2]; +} + +static void randomize_segments2(int whitemode, int nsegments) +{ + int i = 0; + + for (i = 0; i < nsegments; i++) { + if (i % 3 == 2) + colors[i][0] = whitemode * 255, + colors[i][1] = whitemode * 255, colors[i][2] = + whitemode * 255; + else if (i % 3 == 0) + colors[i][0] = (!whitemode) * 255, + colors[i][1] = (!whitemode) * 255, + colors[i][2] = (!whitemode) * 255; + else + colors[i][0] = (int) XaoS_random() % 256, + colors[i][1] = (int) XaoS_random() % 256, + colors[i][2] = (int) XaoS_random() % 256; + } + colors[i - 1][0] = colors[0][0]; + colors[i - 1][1] = colors[0][1]; + colors[i - 1][2] = colors[0][2]; +} + +static void randomize_segments(int whitemode, int nsegments) +{ + int i = 0; + if (whitemode) { + colors[0][0] = 255, colors[0][1] = 255, colors[0][2] = 255; + for (i = 0; i < nsegments; i += 2) { + if (i != 0) { + colors[i][0] = (int) XaoS_random() % 256, + colors[i][1] = (int) XaoS_random() % 256, + colors[i][2] = (int) XaoS_random() % 256; + } + if (i + 1 < nsegments) + colors[i + 1][0] = (int) XaoS_random() % 35, + colors[i + 1][1] = (int) XaoS_random() % 35, + colors[i + 1][2] = (int) XaoS_random() % 35; + } + } else { + for (i = 0; i < nsegments; i += 2) { + colors[i][0] = (int) XaoS_random() % 35, + colors[i][1] = (int) XaoS_random() % 35, + colors[i][2] = (int) XaoS_random() % 35; + if (i + 1 < nsegments) + colors[i + 1][0] = (int) XaoS_random() % 256, + colors[i + 1][1] = (int) XaoS_random() % 256, + colors[i + 1][2] = (int) XaoS_random() % 256; + } + } + colors[i - 1][0] = colors[0][0]; + colors[i - 1][1] = colors[0][1]; + colors[i - 1][2] = colors[0][2]; +} + +#define MYLONG_MAX 0xffffff +#define rrandom(i) ((int)(((int)XaoS_random()/(double)MYLONG_MAX)*(i))) +/*Do not use modulo type random since it should bring very different results + *for slightly different sizes + */ + +int mkpalette(struct palette *c, int seed, int algorithm) +{ + int i, ncolors = c->size; + int whitemode; + int i1; + + context = c; + needupdate = 0; + + if (c->flags & DONOTCHANGE) + return 0; + XaoS_srandom(seed); + seed = (int) XaoS_random(); + whitemode = (int) XaoS_random() % 2; + + if ((c->flags & UNKNOWNENTRIES) || !c->size) { + maxentries = context->maxentries - nprecells; + segmentsize = (rrandom(maxentries / 2)) & (~3); + if (segmentsize < 1) + segmentsize = 1; + } else { + if (maxentries > 8) { + int qq = 255; + + maxentries = context->maxentries - nprecells; + segmentsize = rrandom(qq / 3 + 4); + segmentsize += rrandom(qq / 3 + 4); + segmentsize += rrandom(qq / 3 + 4); + segmentsize += rrandom(qq / 3 + 4); /*Make smaller segments with higher probability */ + + segmentsize = abs(segmentsize / 2 - qq / 3 + 3); + if (segmentsize < 8) + segmentsize = 8; + if (segmentsize > maxentries / 3) + segmentsize = maxentries / 3; + } + } + + if (c->flags & UNKNOWNENTRIES) + i = rrandom(maxentries); + else + i = (maxentries + segmentsize - 5) / segmentsize; + + if (i < 0) + i = 1; + if (i > MAXNSEGMENTS) + i1 = MAXNSEGMENTS; + else + i1 = i; + + XaoS_srandom(seed); + + switch (algorithm) { + case 2: + randomize_segments3(whitemode, i1); + break; + case 1: + randomize_segments2(whitemode, i1); + break; + case 0: + randomize_segments(whitemode, i1); + } + mksmooth(i1, i); + + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + + return 0; +} + +int mkstereogrampalette(struct palette *c) +{ + int i, ncolors = c->size; + context = c; + needupdate = 0; + for (i = 0; i < 16; i++) + allocate(i * 4, i * 4, i * 16, i == 0); + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + return 0; +} + +int mkstarfieldpalette(struct palette *c) +{ + int i, ncolors = c->size; + context = c; + needupdate = 0; + for (i = 0; i < 16; i++) + if (i % 2) + allocate(i * 4, i * 4, i * 16, i == 0); + else + allocate(i * 16, i * 16, i * 16, i == 0); + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + return 0; +} + +int mkblurpalette(struct palette *c) +{ + int i, ncolors = c->size; + context = c; + needupdate = 0; + for (i = 0; i < 63; i++) + allocate(i * 2, i * 2, i * 4, i == 0); + allocate(i * 2, i * 2, i * 4 - 1, 0); + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + return 0; +} + +int mkgraypalette(struct palette *c) +{ + int i, ncolors = c->size; + context = c; + needupdate = 0; + for (i = 0; i < 64; i++) + allocate(i * 4, i * 4, i * 4, i == 0); + for (i = 0; i < 16; i++) + allocate(255, 255 - i * 16, 255 - i * 16, 0); + for (i = 0; i < 16; i++) + allocate(255 - i * 16, 0, 0, 0); + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + return 0; +} + +int mkdefaultpalette(struct palette *c) +{ + int i, ncolors = c->size; + context = c; + needupdate = 0; + segmentsize = 8; + + if (c->flags & DONOTCHANGE) + return 0; + memcpy(colors, colors1, sizeof(colors1)); + maxentries = context->maxentries - nprecells; + if (c->flags & UNKNOWNENTRIES) + i = 128 / 8; + else + i = (maxentries + 3) / 8; + if (i < 0) + i = 1; + mksmooth(255 / 8, i); + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + return 1; + } + return 0; +} + +int shiftpalette(struct palette *c, int shift) +{ + if (!c->size) + return 0; + + while (shift < 0) + shift += c->size - 1; + shift = shift % (c->size - 1); + + if (!shift) + return 0; + + if (c->cyclecolors != NULL) { + if (c->flags & UNFINISHED) { + cycle_entries(c, shift); + } else { + c->cyclecolors(c, shift); + } + return 0; + } + + if (c->type & (TRUECOLOR | TRUECOLOR24 | TRUECOLOR16)) { + int i; + int i3; + int *co; + + if (shift > 0) + shift %= c->size - 1; + else + shift = -((-shift) % (c->size - 1)); + if (!shift) + return 0; + co = (int *) malloc(c->size * sizeof(*co)); + memcpy(co, c->pixels, sizeof(*co) * c->size); + i3 = (c->size - 1 + shift) % (c->size - 1) + 1; + for (i = 1; i < c->size; i++) { + c->pixels[i] = co[i3]; + i3++; + if (i3 >= c->size) + i3 = 1; + } + c->version++; + free(co); + } + return 1; +} + +static int allocrgb(struct palette *c, int r1, int g1, int b1) +{ + int r, g, b; + int f = 1; + for (g = 0; g < g1; g++) + for (b = 0; b < b1; b++) { + for (r = 0; r < r1; r++) { + if (!allocate + (r * 255 / (r1 - 1), g * 255 / (g1 - 1), + b * 255 / (b1 - 1), f)) + return 0; + f = 0; + } + } + return 1; +} + +int mkrgb(struct palette *c) +{ + int ncolors = c->size; + int red = 8, green = 8, blue = 4; + + context = c; + needupdate = 0; + + if (c->flags & UNKNOWNENTRIES) { + while (blue > 0) { + if (allocrgb(c, red, green, blue)) + break; + red--; + if (allocrgb(c, red, green, blue)) + break; + green--; + if (allocrgb(c, red, green, blue)) + break; + red--; + if (allocrgb(c, red, green, blue)) + break; + green--; + if (allocrgb(c, red, green, blue)) + break; + blue--; + } + } else { + number_t n = + pow((c->maxentries - nprecells) / (0.5 * 0.2 * 0.3), 1.0 / 3); + green = (int) (n * 0.5); + blue = (int) (n * 0.2); + red = (int) (n * 0.3); + while ((blue + 1) * red * green < (c->maxentries - nprecells)) + blue++; + while ((red + 1) * blue * green < (c->maxentries - nprecells)) + red++; + while ((green + 1) * blue * red < (c->maxentries - nprecells)) + green++; + allocrgb(c, red, green, blue); + } + + if (!(c->flags & FINISHLATER)) { + if (c->allocfinished != NULL) + c->allocfinished(c); + } else + c->flags |= UNFINISHED; + if (context->size != ncolors || needupdate) { + context->version++; + } + + return red * 256 * 256 + green * 256 + blue; +} |