home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Part 3
- */
-
- #include <stdio.h>
-
- struct rgb {int r, g, b;};
-
- extern int pals, colors;
- extern long colorerr [256];
- extern struct rgb cmap [256], palette [32];
-
- struct adjcell {
- unsigned char color;
- int dist;
- };
-
- /* Select and set palette */
- setpalette ()
- {
- char *calloc ();
- struct adjcell **adj;
- static marked [256];
- int color, color2, r, g, b, len, dup, unmarked, marks;
- int mindist, mincolor, distance, colperpal, i, pal, radius;
- struct adjcell *p;
- struct rgb *rgbp;
-
- /* Clear marked array */
- for (color = 0; color < colors; color++)
- marked [color] = 0;
- marks = 0;
-
- /* Always assign background */
- palette [0] = cmap [0];
- pals = 1;
- if (!marked [0]) {
- marked [0] = -1;
- marks++;
- }
- printf ("Colours after removing background colour = %d\n", colors-marks);
-
- /* Mark off colors that are never used */
- calcremap ();
- scanpic ();
- for (color = 0; color < colors; color++)
- if ((colorerr [color] == 0L) && !marked [color]) {
- marked [color] = -1;
- marks++;
- }
- printf ("Colours after removing no-error colours = %d\n", colors-marks);
-
- /* Mark off duplicates */
- for (color = 0; color < colors; color++)
- if (!marked [color]) {
- r = cmap [color].r;
- g = cmap [color].g;
- b = cmap [color].b;
- for (color2 = color+1; color2 < colors; color2++)
- if (!marked [color2]) {
- rgbp = &cmap [color2];
- if ((r == rgbp->r) && (g == rgbp->g) && (b == rgbp->b)) {
- marked [color2] = -1;
- marks++;
- }
- }
- }
- printf ("Colours after removing duplicate colours = %d\n", colors-marks);
-
- pals = 16;
- unmarked = colors - marks;
- colperpal = unmarked / (pals - 1);
- if (colperpal == 0)
- colperpal = 1;
- printf ("Colours per palette colour = %d\n", colperpal);
-
- /* Select and set palette based on sorted lists */
- /* Create sorted-by-distance list of colors for each colors */
- /* Leave out marked colors */
- printf ("Sorting colour\n");
- adj = (struct adjcell **) calloc (colors, sizeof (struct adjcell *));
- if (adj == NULL)
- fatalerr ("Out of memory");
- for (color = 0; color < colors; color ++) {
- if (marked [color])
- adj [color] = NULL;
- else {
- adj [color] = (struct adjcell *)
- calloc (unmarked, sizeof (struct adjcell));
- if (adj [color] == NULL)
- fatalerr ("Out of memory");
- len = 0;
- r = cmap [color].r;
- g = cmap [color].g;
- b = cmap [color].b;
- for (color2 = 0; color2 < colors; color2 ++)
- if (!marked [color2])
- insertheap (
- color2,
- rgberr (
- r, g, b,
- cmap [color2].r,
- cmap [color2].g,
- cmap [color2].b),
- &len,
- adj [color]);
- heapsort (len, adj [color]);
- }
- printf ("%d\n\x1BM", color);
- }
- printf (" "); /* Erase sorting count */
- printf ("\x1B[1F\x1B[40K\n\x1BM"); /* Erase sorting message */
-
- /* Select and set palette based on sorted lists */
- for (pal = 1; pal < pals; pal ++) {
- radius = 0;
- mincolor = 0;
- mindist = 32000;
- if (marks >= colors)
- goto noassign;
- /* Pick the best color to assign to the palette */
- for (color = 1; color < colors; color ++)
- if (!marked [color]) {
- distance = 0;
- p = adj [color];
- for (i = 0; i < colperpal; i ++) {
- while (marked [p->color])
- p ++;
- distance += p->dist;
- p ++;
- }
- if (distance < mindist) {
- mindist = distance;
- mincolor = color;
- }
- }
- /* Mark off mincolor and the colors around it */
- p = adj [mincolor];
- radius = 0;
- for (i = 0; i < colperpal; i++) {
- while (marked [p->color])
- p ++;
- marked [p->color] = -1;
- marks++;
- if (p->dist > radius)
- radius = p->dist;
- p ++;
- }
- noassign:
- palette [pal] = cmap [mincolor];
- printf ("Palette %3d = colour %3d, radius = %3d\n\x1BM",
- pal, mincolor, radius);
- }
-
- /* Free up some memory */
- for (color = 0; color < colors; color++)
- if (adj [color] != NULL)
- free (adj [color]);
- free (adj);
-
- printf ("\x1B[4F"); /* Move to first line of stats */
- printf ("\x1B[J"); /* Erase to end of display */
- }
-
- /* Insert a value into a heap */
- insertheap (color, dist, len, adjline)
- int *len;
- struct adjcell *adjline;
- {
- struct adjcell *heap = adjline - 1;
- struct adjcell *p, *q, temp;
- int i;
-
- i = ++(*len);
- heap [i].color = color;
- heap [i].dist = dist;
- while ((i > 1) && ((p=heap+i)->dist > (q=heap+(i>>1))->dist)) {
- temp = *p;
- *p = *q;
- *q = temp;
- i >>= 1;
- }
- }
-
- /* Rearrange heap into sorted list */
- heapsort (last, adjline)
- struct adjcell *adjline;
- {
- struct adjcell *h = adjline - 1;
- struct adjcell *q, temp;
- int n = last;
- int i;
-
- for (i = n; i >= 2; i--) {
- q = h + last;
- temp = *adjline;
- *adjline = *q;
- *q = temp;
- last --;
- pushdown (last, h, 1);
- }
- }
-
- /* Part of heapsort */
- pushdown (last, h, start)
- struct adjcell *h;
- {
- struct adjcell *p, *q, temp;
- int i = start;
- int j = i;
- int last2 = last >> 1;
-
- while ((i <= last2) && (i == j)) {
- j = i << 1;
- if (j < last) {
- if (h [j].dist < h [j + 1].dist)
- j++;
- }
- if ((p=h+i)->dist < (q=h+j)->dist) {
- temp = *p;
- *p = *q;
- *q = temp;
- i = j;
- }
- }
- }
-
-