home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * FILE: color.c
- * DESC: This file contains the color routines used by morph,
- * dissolve and fix.
- *
- * HISTORY: Created 3/18/1993
- * LAST CHANGED: 5/ 6/1993
- *
- * Copyright (c) 1992 by Scott Anderson
- *
- ****************************************************************/
-
- #include <stdio.h>
- #include <memory.h>
-
- #include "define.h"
-
- /* ----------------------DEFINES------------------------------ */
-
- /* ----------------------TYPEDEFS/STRUCTS--------------------- */
-
- /* ----------------------PROTOTYPES--------------------------- */
-
- int closestColor(int r, int g, int b, PALETTE *palPtr);
- void collapseColors(PALETTE *palPtr);
- int mergePalette(PICTURE *pic);
- int remapPicture(PICTURE *picPtr, PALETTE *palPtr);
- int initFreq();
-
- /* ----------------------EXTERNALS---------------------------- */
-
- /* set from last picture loaded */
- extern int Xmin, Ymin, Xmax, Ymax;
-
- /* ----------------------GLOBAL DATA-------------------------- */
-
- /* number of colors in tweened image before reduction*/
- int Ncolors;
-
- /* r, g, b frequency counter array */
- unsigned int far Freq[MAX_COMP][MAX_COMP][MAX_COMP];
-
- /* tweened images red, grn, and blu components*/
- unsigned char far Red[MAX_WIDE][MAX_TALL];
- unsigned char far Grn[MAX_WIDE][MAX_TALL];
- unsigned char far Blu[MAX_WIDE][MAX_TALL];
-
- PALETTE TweenPal; /* resulting palette */
-
- /*****************************************************************
- * FUNC: void collapseColors(PALETTE *palPtr)
- *
- * DESC: Collapse the colors in the Freq table until
- * Ncolors < COLORS, then put it in the given color palette.
- *****************************************************************/
-
- void
- collapseColors(PALETTE *palPtr)
- {
- int freqCutoff;
- int r, g, b;
- int index;
- int ncolors;
-
- static int freqCount[MAX_FREQ+1];
-
- memset(freqCount, 0, sizeof freqCount);
- for (r = 0; r < MAX_COMP; r++)
- for (g = 0; g < MAX_COMP; g++)
- for (b = 0; b < MAX_COMP; b++)
- freqCount[Freq[r][g][b]]++;
-
- ncolors = 0;
- for (freqCutoff = COLORS-1; freqCutoff > 1; freqCutoff--) {
- ncolors += freqCount[freqCutoff];
- if (ncolors > COLORS) break;
- }
-
- /* Collapse color space to 256 colors */
- r = g = b = 0;
- while (Ncolors >= COLORS) {
- for (; r < MAX_COMP; r++, g=0) {
- for (; g < MAX_COMP; g++, b=0) {
- for (; b < MAX_COMP; b++) {
- if (Freq[r][g][b] && Freq[r][g][b]
- <= freqCutoff)
- goto castOut; /* the ultimate no no */
- }
- }
- }
- r = g = b = 0;
- freqCutoff++;
- continue;
- castOut:
- Freq[r][g][b] = 0; /* just remove this low freq color */
- Ncolors--;
- }
-
- /* build a palette out of all the remaining non zero freq's */
- index = 0;
- for (r = 0; r < MAX_COMP; r++)
- for (g = 0; g < MAX_COMP; g++)
- for (b = 0; b < MAX_COMP; b++)
- /* we have a color we need to map */
- if (Freq[r][g][b]) {
- palPtr->c[index].r = r;
- palPtr->c[index].g = g;
- palPtr->c[index].b = b;
- /* remember index in palette */
- Freq[r][g][b] = index;
- index++;
- }
- }
-
- /*****************************************************************
- * FUNC: int closestColor(int r, int g, int b, PALETTE *palPtr)
- *
- * DESC: return the palette index of the color closest to rgb.
- *****************************************************************/
-
- int
- closestColor(int r, int g, int b, PALETTE *palPtr)
- {
- int index;
- int distance;
- int min_distance = 3200; /* a big number */
- int min_index;
-
- /* The value in Freq is now the index into the color table */
- if (Freq[r][g][b]) return Freq[r][g][b];
-
- /* If zero, search for the closest color */
- for (index = 1; index < Ncolors; index++) {
- /* this is really the distance squared, but it works */
- distance = SQUARE (r - palPtr->c[index].r) +
- SQUARE (g - palPtr->c[index].g) +
- SQUARE (b - palPtr->c[index].b);
- if (distance < min_distance) {
- min_distance = distance;
- min_index = index;
- if (distance <= 2) break; /* close enough! */
- }
- }
- /* New index - for future reference */
- Freq[r][g][b] = min_index;
- return min_index;
- }
-
- /*****************************************************************
- * FUNC: int mergePalette(PICTURE *picPtr)
- *
- * DESC: Merge a palette into Freq count table.
- *****************************************************************/
-
- int
- mergePalette(PICTURE *picPtr)
- {
- int r, g, b;
- unsigned int pos;
- unsigned char index;
- PALETTE *palPtr = &picPtr->pal;
- unsigned char far *bufPtr = picPtr->pixmap;
-
- for (pos = 0; pos < MAX_BYTES; pos++) {
- index = *bufPtr++;
- r = palPtr->c[index].r;
- g = palPtr->c[index].g;
- b = palPtr->c[index].b;
- if (Freq[r][g][b] == 0) /* A new color */
- Ncolors++;
- if (Freq[r][g][b] < MAX_FREQ) /* Keep it managable */
- Freq[r][g][b]++;
- }
- }
-
- /*****************************************************************
- * FUNC: int remapPicture(PICTURE *picPtr, PALETTE *palPtr)
- *
- * DESC: Remap a picture with a different palette.
- *****************************************************************/
-
- int
- remapPicture(PICTURE *picPtr, PALETTE *palPtr)
- {
- int x, y;
- int index;
- int r, g, b;
- unsigned int pos;
- unsigned char lookup[COLORS];
- unsigned char far *bufPtr;
-
- /* Create the cross-reference lookup table */
- for (index = 0; index < COLORS; index++) {
- r = picPtr->pal.c[index].r;
- g = picPtr->pal.c[index].g;
- b = picPtr->pal.c[index].b;
- lookup[index] = closestColor(r, g, b, palPtr);
- }
-
- /* Save the new palette in the picture's palette */
- for (index = 0; index < COLORS; index++) {
- picPtr->pal.c[index].r = palPtr->c[index].r;
- picPtr->pal.c[index].g = palPtr->c[index].g;
- picPtr->pal.c[index].b = palPtr->c[index].b;
- }
-
- /* Remap the individual pixels to point to the new colors */
- for (bufPtr = picPtr->pixmap, pos = 0; pos < MAX_BYTES;
- bufPtr++, pos++)
- *bufPtr = lookup[*bufPtr];
- }
- /*****************************************************************
- * FUNC: int initFreq()
- *
- * DESC: zero out the frequency color space table
- *****************************************************************/
-
- int
- initFreq()
- {
- int bytes = (sizeof Freq) / 2;
-
- _fmemset(Freq, 0, bytes);
- /* divide because of element size */
- _fmemset(Freq+(bytes/sizeof *Freq), 0, bytes);
-
- /* Guarantee a black color */
- Freq[0][0][0] = MAX_FREQ;
- /* a grey color */
- Freq[MID_COMP-1][MID_COMP-1][MID_COMP-1] = MAX_FREQ;
- /* and a white color */
- Freq[(long)MAX_COMP-1][MAX_COMP-1][MAX_COMP-1] = MAX_FREQ;
- Ncolors = 3;
- }
-
-
-