home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c185 / 2.ddi / OWLSRC.EXE / CSCAPE / SOURCE / PCSQCMAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-06  |  11.3 KB  |  385 lines

  1. /*
  2.     pcsqcmap.c
  3.  
  4.     % Compress the color palette for given pixel maps into a given color range.
  5.  
  6.     2/22/88 By Ted.
  7.  
  8.     OWL 1.1
  9.     Copyright (c) 1988, 1989 by Oakland Group, Inc.
  10.     ALL RIGHTS RESERVED.
  11.  
  12.     Revision History:
  13.     -----------------
  14. */
  15.  
  16. #include "pcpriv.h"
  17.  
  18. typedef struct {
  19.     pmap_type *maps;    /* array of pmaps to be translated to new colormap */
  20.     int nmaps;            /* number of pmaps in array */
  21.     ocolmap_type cmap;    /* old color map */
  22.     unsigned short hist[256];/* histogram of color frequency in pmap */
  23.     byte swaptab[256];    /* pixel map table for mapping pmap to new colormap */
  24.     unsigned nunpicked;    /* number of unpicked colors in new table */
  25.     byte picktab[256];    /* map table from picked color in old map to new map */
  26.     byte nopickval;        /* place holder val for unpicked colors in picktab */
  27. } IMAGE;
  28.  
  29. #define inithist(hist)            memset(hist, 0, 256*sizeof(unsigned))
  30. #define initbtab(ptab, val)        memset(ptab, val, 256*sizeof(byte))
  31. #define OC_BLACK                0,0,0
  32.  
  33. OSTATIC void DIGPRIV pal_slide(_arg2(IMAGE *image, ocolmap_type crange));
  34. OSTATIC void DIGPRIV pal_pickcols(_arg2(IMAGE *image, ocolmap_type crange));
  35. OSTATIC void DIGPRIV pal_match(_arg2(IMAGE *image, ocolmap_type tcmap));
  36. OSTATIC boolean DIGPRIV pickcol(_arg3(IMAGE *image, ocolmap_type crange, int next));
  37. OSTATIC byte DIGPRIV markpick(_arg2(IMAGE *image, unsigned pick));
  38. OSTATIC void DIGPRIV initpick(_arg1(IMAGE *image));
  39. OSTATIC int DIGPRIV dohist(_arg1(IMAGE *image));
  40. OSTATIC void DIGPRIV initcswap(_arg1(byte *swaptab));
  41. OSTATIC void DIGPRIV pmap_cswap(_arg2(pmap_type pmap, byte *swaptab));
  42. OSTATIC void DIGPRIV bhist(_arg3(byte *buf, unsigned bufsize, unsigned short *histtab));
  43.  
  44. /* nearestc.asm */
  45. opixval DIGPRIV ocolmap_nearestcol(_arg2(orgb_struct *rgb, ocolmap_type cmap));
  46.  
  47. /* bxlat.asm */
  48. void DIGPRIV bxlat(_arg3(byte *bufaddr, unsigned bufsize, byte *swaptab));
  49. /* -------------------------------------------------------------------------- */
  50.  
  51. void DIGPRIV pc_squeezecmap(pmap, cmap, crange)
  52.     pmap_type pmap;
  53.     ocolmap_type cmap;        /* cmap belonging to pmaps */
  54.     ocolmap_type crange;    /* color range to be squeezed into */
  55. /*
  56.     Compress the color palette for a given set of pixel maps into a
  57.     given color range.
  58. */
  59. {
  60.     IMAGE image;
  61.     
  62.     if (pmap == NULL || crange == NULL) {
  63.         return;
  64.     }
  65.     /* If no cmap is given, put default colors in crange */ 
  66.     if (cmap == NULL) {
  67.         ocolmap_set(crange, disp_GetDefColMapp());
  68.         return;
  69.     }
  70.     image.maps = &pmap;
  71.     image.nmaps = 1;
  72.     image.cmap = cmap;
  73.  
  74. /* If all colors are allocated, no need to squeeze */
  75.     if (crange->nentries >= cmap->nentries) {
  76.         if (crange->firstpix == cmap->firstpix) {
  77.             /* Color range in place; just copy it */
  78.             ocolmap_set(crange, cmap);
  79.         }
  80.         else {
  81.             /* Color range can be slid to fit */
  82.             pal_slide(&image, crange);    /* slide color range into place */
  83.             pal_match(&image, crange);    /* match pmap to new colors */
  84.         }
  85.     }
  86.     else {    /* Must squeeze */
  87.         if (crange->nentries >= dohist(&image)) {
  88.             /* Can just shuffle by throwing out unused colors */
  89.             pal_slide(&image, crange);    /* slide color range into place */
  90.             pal_match(&image, crange);        /* match pmap to new colors */
  91.         }
  92.         else {
  93.             /* Must really squeeze */
  94.  
  95.             /* Clear out top 2 bits of each rgb level - squeeze funcs handle 6 bit levels */
  96.             dig_shiftcmap(cmap, 2);
  97.  
  98.             pal_pickcols(&image, crange);    /* squeeze colors into smaller range */
  99.             pal_match(&image, crange);        /* match pmap to new colors */
  100.  
  101.             /* Restore levels to 8-bit values */
  102.             dig_shiftcmap(cmap, -2);
  103.             dig_shiftcmap(crange, -2);
  104.         }
  105.     }
  106. }
  107. /* -------------------------------------------------------------------------- */
  108.  
  109. static void DIGPRIV pal_slide(image, crange)
  110.     IMAGE *image;
  111.     ocolmap_type crange;
  112. /*
  113.     slide color range into place
  114.     (sets up image->picktab & crange rgb entries)
  115. */
  116. {
  117.     int iscol, idcol, firstdcol, lastscol;
  118.     boolean doall;
  119.  
  120.     /* If crange has room for even unused colors, take them along for the ride */
  121.     doall = (crange->nentries >= image->cmap->nentries);
  122.  
  123.     iscol = (int) image->cmap->firstpix;
  124.     firstdcol = (int) crange->firstpix;
  125.     idcol = firstdcol;
  126.     lastscol = iscol + image->cmap->nentries - 1;
  127.  
  128.     image->nopickval = (byte)firstdcol-1;        /* this will not get picked */
  129.     initbtab(image->picktab, image->nopickval);
  130.  
  131.     for ( ; iscol <= lastscol; iscol++) {
  132.         /* If a color is used or if we have room for it, take it */
  133.         if (doall || image->hist[iscol] != 0) {
  134.             ocolmap_getcolor(image->cmap, (opixval)iscol,
  135.                                     crange, (opixval)idcol);
  136.             image->picktab[iscol] = (byte)idcol++;
  137.         }
  138.         else {    /* If color is unused, skip it and mark it as picked by mapping it to first dcol */
  139.             image->picktab[iscol] = (byte)firstdcol;
  140.         }
  141.     }
  142. }
  143. /* -------------------------------------------------------------------------- */
  144.  
  145. static void DIGPRIV pal_pickcols(image, crange)
  146.     IMAGE *image;
  147.     ocolmap_type crange;
  148. /*
  149.     Squeeze colors from image cmap into smaller crange
  150.     (sets up image->picktab & crange rgb entries)
  151. */
  152. {
  153.     int next, last;
  154.  
  155. /* If crange starts at 0, use nentries as place marker instead of 0 */
  156.     if ((int)crange->firstpix != 0 || crange->nentries == 256)
  157.             image->nopickval = 0;
  158.     else    image->nopickval = (byte)(((int)crange->firstpix) + crange->nentries);
  159.  
  160.     initbtab(image->picktab, image->nopickval);
  161.  
  162.     initpick(image);
  163.  
  164.     next = (int) crange->firstpix;
  165.     last = next + crange->nentries - 1;
  166.  
  167.     for (;;) {
  168.         if (pickcol(image, crange, next)) {
  169.             if (++next > last) break;
  170.         }
  171.         else break;        /* if no more can be picked, quit */
  172.     }
  173. /* Set leftover colors to black */
  174.     for ( ; next <= last; next++) {
  175.         ocolmap_setpixrgb(crange, (opixval) next, OC_BLACK);
  176.     }
  177. }
  178. /* -------------------------------------------------------------------------- */
  179.  
  180. static void DIGPRIV pal_match(image, tcmap)
  181.     IMAGE *image;
  182.     ocolmap_type tcmap;
  183. /*
  184.     Match image colors to target colormap
  185.     (construct color swap translation table from image to target cmap
  186.     and then do the swap on image pmap(s))
  187. */
  188. {
  189.     int ipix, jpix, ifirst, ilast;
  190.     int ipm;
  191.     int first, last;
  192.     orgb_struct *ifirstentry;
  193.  
  194.     first = (int)tcmap->firstpix;
  195.     last = first + tcmap->nentries - 1;
  196.  
  197. /* Map any image colors not defined in image cmap to first target color */
  198.     initbtab(image->swaptab, first);
  199.  
  200.     ifirst = (int)image->cmap->firstpix;
  201.     ilast = ifirst + image->cmap->nentries - 1;
  202.     ifirstentry = ocolmap_entry(image->cmap, ifirst);
  203.     for (ipix = ifirst ; ipix <= ilast; ipix++) {
  204.         
  205.     /* First check if we've picked this color */
  206.         if (image->picktab[ipix] != image->nopickval) {
  207.             image->swaptab[ipix] = image->picktab[ipix];
  208.             goto LOOP;
  209.         }
  210.     /* Next check if we've already done it */
  211.         for (jpix = ifirst; jpix < ipix; jpix++) {
  212.             if (ocolmap_samecolor(image->cmap, (opixval) ipix,
  213.                                     image->cmap, (opixval) jpix)) {
  214.                 image->swaptab[ipix] = image->swaptab[jpix];
  215.                 goto LOOP;
  216.             }
  217.         }
  218.     /* Then check if we're already there */
  219.         if (ipix >= first && ipix <= last) {
  220.             if (ocolmap_samecolor(image->cmap, (opixval)ipix,
  221.                                         tcmap, (opixval)ipix)) {
  222.                 image->swaptab[ipix] = (byte)ipix;
  223.                 goto LOOP;
  224.             }
  225.         }
  226.     /* If those didn't work, do the search */
  227.         image->swaptab[ipix] = 
  228.             (byte) ocolmap_nearestcol(ifirstentry + (ipix-ifirst), tcmap);
  229. LOOP: ;
  230.     }
  231. /* Finally, do the color swap translation on the pmap image buffers */
  232.     for (ipm = 0; ipm < image->nmaps; ipm++) {
  233.         if (image->maps[ipm] != NULL) {
  234.             pmap_cswap(image->maps[ipm], image->swaptab);
  235.         }
  236.     }
  237. }
  238. /* -------------------------------------------------------------------------- */
  239.  
  240. static void DIGPRIV initpick(image)
  241. IMAGE *image;
  242. {
  243.     int ipix, firstpix, lastpix;
  244. /*
  245.     Note- The image swaptab is used for a different purpose here than in
  246.     pal_match.  Here it is used to speed picking an unpicked color at random
  247.     It is used by the matching algorithm, not the mixing one, so at this
  248.     point it is ok to make alternate use of it.
  249. */
  250.  
  251.     /* Mark out unused colors by marking them as already picked */
  252.     /* (Count down instead of up to avoid side effects of markpick) */
  253.  
  254.     image->nunpicked = 256;
  255.     initcswap(image->swaptab);
  256.  
  257.     firstpix = (int)image->cmap->firstpix;
  258.     lastpix = firstpix + image->cmap->nentries - 1;
  259.  
  260.     for (ipix = 256-1; ipix >= 0; ipix--) {
  261.         if (ipix > lastpix || image->hist[ipix] == 0 || ipix < firstpix) {
  262.             markpick(image, ipix);
  263.         }
  264.     }
  265. }
  266. /* -------------------------------------------------------------------------- */
  267.  
  268. static boolean DIGPRIV pickcol(image, crange, next)
  269.     IMAGE *image;
  270.     ocolmap_type crange;
  271.     int next;
  272. {
  273.     byte pick;
  274.     int ipix;
  275.  
  276. LOOP:
  277.     if (image->nunpicked == 0) return FALSE;
  278.  
  279. /* Get remapped pick value and also mark that choice as picked */
  280.     pick = markpick(image, rand());
  281.     
  282. /* Check if we've already done it */
  283.     for (ipix = (int)crange->firstpix; ipix < next; ipix++) {
  284.         if (ocolmap_samecolor(crange, (opixval) ipix,
  285.                             image->cmap, (opixval) pick)) {
  286.             goto LOOP;    /* Already had that one; go get another */
  287.         }
  288.     }
  289. /* It's a new color; make an entry for it */
  290.     ocolmap_getcolor(image->cmap, (opixval) pick, crange, (opixval) next);
  291.     image->picktab[pick] = (byte) next;
  292.     return(TRUE);
  293. }
  294. /* -------------------------------------------------------------------------- */
  295.  
  296. static byte DIGPRIV markpick(image, pick)
  297.     IMAGE *image;
  298.     unsigned pick;
  299. /*
  300.     Pick a value, make sure it never gets picked again
  301.     (returns an unpicked value even though 'pick' may have been picked before)
  302. */
  303. {
  304.     byte realpick;
  305.  
  306.     pick %= image->nunpicked;
  307.  
  308. /* Get out value just picked */
  309.     realpick = image->swaptab[pick];
  310.     image->nunpicked--;
  311.  
  312. /* Slide remaining unpicked values into space just vacated */
  313.     if (pick < image->nunpicked) {
  314.         memcpy(&image->swaptab[pick],
  315.                 &image->swaptab[pick+1],
  316.                 image->nunpicked - pick);
  317.     }
  318. /* Zero out the space just slid out of */
  319.     image->swaptab[image->nunpicked] = 0;
  320.  
  321.     return(realpick);
  322. }
  323. /* -------------------------------------------------------------------------- */
  324.  
  325. static int DIGPRIV dohist(image)
  326.     IMAGE *image;
  327. {
  328.     int ipm, icol, nused, lastpix;
  329.  
  330.     inithist(image->hist);
  331.     for (ipm = 0; ipm < image->nmaps; ipm++) {
  332.         if (image->maps[ipm] != NULL) {
  333.             bhist(pcpmap_pixbuf(image->maps[ipm]),
  334.                     (unsigned) pcpmap_GetPlaneSize(image->maps[ipm]),
  335.                     image->hist);
  336.         }
  337.     }
  338.     icol = (int)image->cmap->firstpix;
  339.     lastpix = icol + image->cmap->nentries - 1;
  340.  
  341.     nused = 0;
  342.     for ( ; icol <= lastpix; icol++) {
  343.         if (image->hist[icol] != 0) nused++;
  344.     }
  345.     return(nused);
  346. }
  347. /* -------------------------------------------------------------------------- */
  348.  
  349. static void DIGPRIV initcswap(swaptab)
  350.     byte *swaptab;
  351. {
  352.     int ipix;
  353.     if (swaptab) {
  354.         for (ipix=0; ipix < 256; ipix++)
  355.             swaptab[ipix] = (byte)ipix;
  356.     }
  357. }
  358. /* -------------------------------------------------------------------------- */
  359.  
  360. static void DIGPRIV pmap_cswap(pmap, swaptab)
  361.     pmap_type pmap;
  362.     byte *swaptab;
  363. {
  364.     if (pcpmap_pixbits(pmap) == 8) {
  365.         bxlat(pcpmap_pixbuf(pmap), (unsigned)pcpmap_GetPlaneSize(pmap), swaptab);
  366.     }
  367. }
  368. /* -------------------------------------------------------------------------- */
  369.  
  370. static void DIGPRIV bhist(buf, bufsize, histtab)
  371.     byte *buf;
  372.     unsigned bufsize;
  373.     unsigned short *histtab;
  374. /*
  375.     Histogram nbytes bytes at buf into word table 'histtab'.
  376.     Table must be pre-initialized; bhist starts incrementing w/o zeroing.
  377. */
  378. {
  379.     for ( ; bufsize > 0; bufsize--) {
  380.         histtab[*(buf++)]++;
  381.     }
  382. }
  383. /* -------------------------------------------------------------------------- */
  384.  
  385.