home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 2 / RISC_DISC_2.iso / pd_share / program / sprtools / c / colours < prev    next >
Encoding:
Text File  |  1994-07-18  |  21.1 KB  |  838 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  * colours.c                                                            *
  4.  * =========                                                            *
  5.  *                                                                      *
  6.  * RISCOS sprite style bitmap processing library                        *
  7.  * Uses spr_info generic bitmap interface from sprite.c library         *
  8.  *                                                                      *
  9.  * Functions to return closest value to desired RGB from sprites        *
  10.  * palette or colour range. A pix_str is used so value <0 & >255        *
  11.  * Palette types can be identified and a fast routine attached to       *
  12.  * the sprite structure.                                                *
  13.  *                                                                      *
  14.  * Version 1.01 (05-May-1994) split from process.c                      *
  15.  *                                                                      *
  16.  * (C) 1994 DEEJ Technology PLC                                         *
  17.  *                                                                      *
  18.  ************************************************************************/
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include "sprite.h"
  24. #include "colours.h"
  25.  
  26. static pix_str *closest_rgb_core(pix_str *rgb, uint*, int);
  27. static pix_str *closest_rgb_gen(spr_info_str *s, pix_str *rgb);
  28. static pix_str *closest_rgb_24(spr_info_str *s, pix_str *rgb);
  29. static pix_str *closest_rgb_15(spr_info_str *s, pix_str *rgb);
  30. static pix_str *closest_rgb_1(spr_info_str *s, pix_str *rgb);
  31. static pix_str *closest_rgb_grey(spr_info_str *s, pix_str *rgb);
  32. static pix_str *closest_rgb_grey8(spr_info_str *s, pix_str *rgb);
  33. static pix_str *closest_rgb_desk8(spr_info_str *s, pix_str *rgb);
  34. static pix_str *closest_rgb_cube(spr_info_str *s, pix_str *rgb);
  35.  
  36. /* global data */
  37.  
  38. static   pix_str      cache[CACHE_SIZE];
  39.  
  40. #ifdef SQR_TABLE
  41. static   int          squares[1024];
  42. #endif
  43.  
  44. #ifdef CACHE_STAT
  45. int cache_calls;
  46. int cache_hits;
  47. int cache_misses;
  48. int cache_used;
  49. #endif
  50.  
  51. /****************************************************************************/
  52.  
  53. /*
  54.  * checks for value in cache
  55.  * returns valid pix_str for hit
  56.  * or 0 and index = cache placement position for a miss
  57.  * s used to check for initial call and sprite changed
  58.  */
  59.  
  60. static pix_str *check_cache(spr_info_str *s, pix_str *rgb, int *index)
  61. {
  62.     static   spr_info_str *last_spr = 0;
  63.     int      i, hash;
  64.  
  65.         if(s != last_spr)
  66.         {
  67. #ifdef SQR_TABLE
  68.             if(last_spr == 0)
  69.             {
  70.                     for(i=-512; i<512; i++)
  71.                     {
  72.                             squares[512+i] = i*i;
  73.                     }
  74.             }
  75. #endif
  76.             /* initialise cache */
  77. #ifdef CACHE_STAT
  78.                 cache_calls  = 0;
  79.                 cache_hits   = 0;
  80.                 cache_misses = 0;
  81.                 cache_used   = 0;
  82. #endif
  83.                 for(i=0; i<CACHE_SIZE; i++)
  84.                 {
  85.                         cache[i].value = -1;
  86.                 }
  87.                 last_spr = s;
  88.         }
  89.  
  90.         /* hash RGB value and check for cache hit */
  91.  
  92.         hash = HASH(rgb->red, rgb->green, rgb->blue);
  93.  
  94. #ifdef CACHE_STAT
  95.         cache_calls++;
  96. #endif
  97.         if(cache[hash].value != -1         &&
  98.            cache[hash].red   == rgb->red   &&
  99.            cache[hash].green == rgb->green &&
  100.            cache[hash].blue  == rgb->blue)
  101.         {
  102. #ifdef CACHE_STAT
  103.             cache_hits++;
  104. #endif
  105.                 return(&cache[hash]); 
  106.         }
  107.  
  108. #ifdef CACHE_STAT
  109.         if(cache[hash].value == -1)
  110.                 cache_used++;
  111.         else
  112.                 cache_misses++;
  113. #endif
  114.  
  115.     *index = hash;
  116.     return(0);
  117. }
  118.  
  119.  
  120. /*
  121.  * general function
  122.  * handles any palette and colour depth
  123.  */
  124.  
  125. pix_str *closest_rgb(spr_info_str *s, pix_str *rgb)
  126. {
  127.     static   spr_info_str *last_spr = 0;
  128.     static   pix_str      close_rgb;
  129.         REGISTER int i;
  130.         REGISTER int r, g, b, r2, g2, b2;
  131.         REGISTER int rd, gd, bd;
  132.         REGISTER int close_diff, diff;
  133.                  int hash;
  134.  
  135.         if(s->bpp == 24)        /* take care of 24 bpp case */
  136.         {
  137.                 RANGE_RGB(rgb->red);
  138.                 RANGE_RGB(rgb->green);
  139.                 RANGE_RGB(rgb->blue);
  140.  
  141.                 close_rgb.red   = rgb->red;
  142.                 close_rgb.green = rgb->green;
  143.                 close_rgb.blue  = rgb->blue;
  144.                 close_rgb.value = (rgb->blue  << 24) |
  145.                                   (rgb->green << 16) |
  146.                                   (rgb->red   <<  8);
  147.  
  148.                 return(&close_rgb);
  149.         }
  150.  
  151.  
  152.         /* initialise cache */
  153.  
  154.         if(s != last_spr)
  155.         {
  156. #ifdef SQR_TABLE
  157.             if(last_spr == 0)
  158.             {
  159.                     for(i=-512; i<512; i++)
  160.                     {
  161.                             squares[512+i] = i*i;
  162.                     }
  163.             }
  164. #endif
  165. #ifdef CACHE_STAT
  166.                 cache_calls  = 0;
  167.                 cache_hits   = 0;
  168.                 cache_misses = 0;
  169.                 cache_used   = 0;
  170. #endif
  171.                 for(i=0; i<CACHE_SIZE; i++)
  172.                 {
  173.                         cache[i].value = -1;
  174.                 }
  175.                 last_spr = s;
  176.         }
  177.  
  178.         if(s->bpp > 8)
  179.         {
  180.                 RANGE_RGB(rgb->red);
  181.                 RANGE_RGB(rgb->green);
  182.                 RANGE_RGB(rgb->blue);
  183.         }
  184.  
  185.         /* hash RGB value and check for cache hit */
  186.  
  187.         hash = HASH(rgb->red, rgb->green, rgb->blue);
  188.  
  189. #ifdef CACHE_STAT
  190.         cache_calls++;
  191. #endif
  192.         if(cache[hash].value != -1         &&
  193.            cache[hash].red   == rgb->red   &&
  194.            cache[hash].green == rgb->green &&
  195.            cache[hash].blue  == rgb->blue)
  196.         {
  197. #ifdef CACHE_STAT
  198.         cache_hits++;
  199. #endif
  200.                 return(&cache[hash]); 
  201.         }
  202. #ifdef CACHE_STAT
  203.         if(cache[hash].value == -1)
  204.                 cache_used++;
  205.         else
  206.                 cache_misses++;
  207. #endif
  208.  
  209.         close_diff = MAX_DIFF;
  210.  
  211.         r = rgb->red;
  212.         g = rgb->green;
  213.         b = rgb->blue;
  214.  
  215.         for(i=0; i<s->cols; i++)
  216.         {
  217.                 if(s->bpp == 15)
  218.                 {
  219.                         /*
  220.                          * special case - use 8 closest values
  221.                          * from corners of 15 bit colour cube
  222.                          * using max span alg for lower 3 bits
  223.                          */
  224.  
  225.                         r2 = (r & 0xF8) | (r >> 5);
  226.                         g2 = (g & 0xF8) | (g >> 5);
  227.                         b2 = (b & 0xF8) | (b >> 5);
  228.  
  229.                         if(r >= r2) rd = 0x11; else rd=-0x11;
  230.                         if(g >= g2) gd = 0x11; else gd=-0x11;
  231.                         if(b >= b2) bd = 0x11; else bd=-0x11;
  232.  
  233.                         if((i & 1) > 0) r2 += rd;
  234.                         if((i & 2) > 0) g2 += gd;
  235.                         if((i & 4) > 0) b2 += bd;
  236.  
  237.                         RANGE_RGB(r2);
  238.                         RANGE_RGB(g2);
  239.                         RANGE_RGB(b2);
  240.  
  241.                         /* only do the 8 calcualtions */
  242.                         if(i==7) i=s->cols;
  243.                 }
  244.                 else
  245.                 {
  246.                         /*
  247.                          * do palette lookup 
  248.                          * assume all sprites now use full 8 bit palette
  249.                          * so no need to copy upper to lower nibbles
  250.                          */
  251.  
  252.                         r2 = (s->palette[i] >> 8)  & 0xFF;
  253.                         g2 = (s->palette[i] >> 16) & 0xFF;
  254.                         b2 = (s->palette[i] >> 24) & 0xFF;
  255.                 }
  256.  
  257.                 /* difference calculation */
  258.  
  259.                 rd = r - r2;
  260.                 gd = g - g2;
  261.                 bd = b - b2;
  262.  
  263.                 /*
  264.                  * diff^2 * weights
  265.                  * full 16 bit wieghts are to big, so shift by 3
  266.                  */
  267.  
  268. /*
  269.                 diff = squares[512+rd] * (RED_WEIGHT   >> WEIGHT_SHIFT) +
  270.                        squares[512+gd] * (GREEN_WEIGHT >> WEIGHT_SHIFT) +
  271.                        squares[512+bd] * (BLUE_WEIGHT  >> WEIGHT_SHIFT);
  272. */
  273. #ifdef SQR_TABLE
  274.                 diff = squares[512+rd] * 3 +
  275.                        squares[512+gd] * 6 +
  276.                        squares[512+bd]; 
  277. #else
  278.                 diff = rd*rd * 3 +
  279.                        gd*gd * 6 +
  280.                        bd*bd; 
  281. #endif
  282.  
  283.                 /* check for better match */
  284.  
  285.                 if(diff < close_diff)
  286.                 {
  287.                         close_diff      = diff;
  288.                         close_rgb.value = i;
  289.                         close_rgb.red   = r2;
  290.                         close_rgb.green = g2;
  291.                         close_rgb.blue  = b2;
  292.  
  293.                         /* short cut for extact match */
  294.  
  295.                         if(diff == 0) i=s->cols;
  296.                 }
  297.         }
  298.  
  299.         /* fixup value for 15 bit special case */
  300.  
  301.         if(s->bpp == 15)
  302.         {
  303.                 close_rgb.value = (close_rgb.red           >> 3) |
  304.                                  ((close_rgb.green & 0xF8) << 2) |
  305.                                  ((close_rgb.blue  & 0xF8) << 7);
  306.         }
  307.  
  308.         /* cache value and return closest colour index & rgb info */
  309.  
  310.         cache[hash] = close_rgb;
  311.  
  312.         return(&close_rgb);
  313. }
  314.  
  315. static pix_str *closest_rgb_core(pix_str *rgb, uint *palette, int cols)
  316. {
  317.         REGISTER int i;
  318.         REGISTER int r, g, b, r2, g2, b2;
  319.         REGISTER int rd, gd, bd;
  320.         REGISTER int close_diff, diff;
  321.     static pix_str close_rgb;
  322.  
  323.         close_diff = MAX_DIFF;
  324.  
  325.         r = rgb->red;
  326.         g = rgb->green;
  327.         b = rgb->blue;
  328.  
  329.         for(i=0; i<cols; i++)
  330.         {
  331.                 /*
  332.                  * do palette lookup 
  333.                  * assume all sprites now use full 8 bit palette
  334.                  * so no need to copy upper to lower nibbles
  335.                  */
  336.  
  337.                 r2 = (palette[i] >> 8)  & 0xFF;
  338.                 g2 = (palette[i] >> 16) & 0xFF;
  339.                 b2 = (palette[i] >> 24) & 0xFF;
  340.  
  341.                 /* difference calculation */
  342.  
  343.                 rd = r - r2;
  344.                 gd = g - g2;
  345.                 bd = b - b2;
  346.  
  347.                 /*
  348.                  * diff^2 * weights
  349.                  * full 16 bit wieghts are to big, so shift by 3
  350.                  */
  351.  
  352. /*
  353.                 diff = squares[512+rd] * (RED_WEIGHT   >> WEIGHT_SHIFT) +
  354.                        squares[512+gd] * (GREEN_WEIGHT >> WEIGHT_SHIFT) +
  355.                        squares[512+bd] * (BLUE_WEIGHT  >> WEIGHT_SHIFT);
  356. */
  357. #ifdef SQR_TABLE
  358.                 diff = squares[512+rd] * 3 +
  359.                        squares[512+gd] * 6 +
  360.                        squares[512+bd]; 
  361. #else
  362.                 diff = rd*rd * 3 +
  363.                        gd*gd * 6 +
  364.                        bd*bd; 
  365. #endif
  366.  
  367.                 /* check for better match */
  368.  
  369.                 if(diff < close_diff)
  370.                 {
  371.                         close_diff      = diff;
  372.                         close_rgb.value = i;
  373.                         close_rgb.red   = r2;
  374.                         close_rgb.green = g2;
  375.                         close_rgb.blue  = b2;
  376.  
  377.                         /* short cut for extact match */
  378.  
  379.                         if(diff == 0) return(&close_rgb);
  380.                 }
  381.         }
  382.         return(&close_rgb);
  383. }
  384.  
  385. /*
  386.  * general function for <=8 bits
  387.  */
  388.  
  389. static pix_str *closest_rgb_gen(spr_info_str *s, pix_str *rgb)
  390. {
  391.     pix_str *close_rgb;
  392.         int     index;
  393.  
  394.     /* check for value in the cache */
  395.  
  396.     if((close_rgb = check_cache(s, rgb, &index))!=0)
  397.         return(close_rgb);
  398.  
  399.     /* #### could use s->has_palette instead of s->colours */
  400.  
  401.     close_rgb = closest_rgb_core(rgb, s->palette, s->cols);
  402.  
  403.         /* cache value and return closest colour index & rgb info */
  404.  
  405.         cache[index] = *close_rgb;
  406.  
  407.         return(close_rgb);
  408. }
  409.  
  410. /*
  411.  * 24bpp - direct return
  412.  */
  413.  
  414. static pix_str *closest_rgb_24(spr_info_str *s, pix_str *rgb)
  415. {
  416.         static   pix_str      close_rgb;
  417.  
  418.         RANGE_RGB(rgb->red);
  419.         RANGE_RGB(rgb->green);
  420.         RANGE_RGB(rgb->blue);
  421.  
  422.         close_rgb.red   = rgb->red;
  423.         close_rgb.green = rgb->green;
  424.         close_rgb.blue  = rgb->blue;
  425.         close_rgb.value = (rgb->blue  << 24) |
  426.                           (rgb->green << 16) |
  427.                           (rgb->red   <<  8);
  428.  
  429.         return(&close_rgb);
  430. }
  431.  
  432. /*
  433.  * 15bpp - finds best match from corners of 5x5x5 bit colour cube
  434.  */
  435.  
  436. static pix_str *closest_rgb_15(spr_info_str *s, pix_str *rgb)
  437. {
  438.     uint          palette[8];
  439.         REGISTER int  i;
  440.     REGISTER int  r,g,b;
  441.     REGISTER int  r2,g2,b2;
  442.     REGISTER int  rd,gd,bd;
  443.         int           index;
  444.     pix_str       *close_rgb;
  445.  
  446.         RANGE_RGB(rgb->red);
  447.         RANGE_RGB(rgb->green);
  448.         RANGE_RGB(rgb->blue);
  449.  
  450.     /* check for value in the cache */
  451.  
  452.     if((close_rgb = check_cache(s, rgb, &index))!=0)
  453.         return(close_rgb);
  454.  
  455.         r = (rgb->red   & 0xF8) | (rgb->red   >> 5);
  456.         g = (rgb->green & 0xF8) | (rgb->green >> 5);
  457.         b = (rgb->blue  & 0xF8) | (rgb->blue  >> 5);
  458.  
  459.         if((rgb->red   >= r) && (r < 255)) rd = 0x11; else rd=-0x11;
  460.         if((rgb->green >= g) && (g < 255)) gd = 0x11; else gd=-0x11;
  461.         if((rgb->blue  >= b) && (b < 255)) bd = 0x11; else bd=-0x11;
  462.  
  463.         for(i=0; i<8; i++)
  464.         {
  465.                 if((i & 1) > 0) r2 = r + rd; else r2 = r;
  466.                 if((i & 2) > 0) g2 = g + gd; else g2 = g;
  467.                 if((i & 4) > 0) b2 = b + bd; else b2 = b;
  468.  
  469.         palette[i] = (b2 << 24) | (g2 << 16) | (r2 << 8);
  470.     }
  471.  
  472.     /* call core routine */
  473.  
  474.     close_rgb = closest_rgb_core(rgb, palette, 8);
  475.  
  476.     /* fix up value field */
  477.  
  478.         close_rgb->value = (close_rgb->red           >> 3) |
  479.                           ((close_rgb->green & 0xF8) << 2) |
  480.                           ((close_rgb->blue  & 0xF8) << 7);
  481.  
  482.         /* cache value and return closest colour index & rgb info */
  483.  
  484.         cache[index] = *close_rgb;
  485.  
  486.         return(close_rgb);
  487. }
  488.  
  489. /*
  490.  * 1 bpp black & white
  491.  */
  492.  
  493. static pix_str *closest_rgb_1(spr_info_str *s, pix_str *rgb)
  494. {
  495.     static  pix_str close_rgb;
  496.     int     grey,index;
  497.     BOOL    inverted = ((s->palette[0] & 0xFFFFFF00)!=0);
  498.  
  499.         grey = rgb->red   * RED_WEIGHT   +
  500.                rgb->green * GREEN_WEIGHT +
  501.                rgb->blue  * BLUE_WEIGHT;
  502.  
  503. #ifdef MULT
  504.     index = (grey >= (0x80 *  GREY_WEIGHT)) ? 1:0;
  505. #else
  506.     index = (grey >= (0x80 << GREY_SHIFT)) ? 1:0;
  507. #endif
  508.  
  509.     close_rgb.value = inverted ? (1-index):index;
  510.     close_rgb.red   = index ? 255:0;
  511.         close_rgb.green = close_rgb.red;
  512.         close_rgb.blue  = close_rgb.red;
  513.  
  514.     return(&close_rgb);
  515. }
  516.     
  517. /*
  518.  * arbitary grey palette
  519.  */
  520.  
  521. static pix_str *closest_rgb_grey(spr_info_str *s, pix_str *rgb)
  522. {
  523.         REGISTER int   i;
  524.         REGISTER int   grey, grey2;
  525.         REGISTER int   close_diff, diff;
  526.     static pix_str close_rgb;
  527.     pix_str        rgb2;
  528.         pix_str       *cache_rgb;
  529.         int            index;
  530.  
  531.     /* check for value in the cache */
  532.  
  533.         grey = rgb->red   * RED_WEIGHT   +
  534.                rgb->green * GREEN_WEIGHT +
  535.                rgb->blue  * BLUE_WEIGHT;
  536.  
  537.     rgb2.red   = grey >> GREY_SHIFT;
  538.     rgb2.green = rgb2.red;
  539.     rgb2.blue  = rgb2.red;
  540.     
  541.     if((cache_rgb = check_cache(s, &rgb2, &index))!=0)
  542.         return(cache_rgb);
  543.  
  544.         close_diff = MAX_DIFF;
  545.  
  546.         for(i=0; i<s->cols; i++)
  547.         {
  548.                 /* do palette lookup */
  549.  
  550.                 grey2 = ((s->palette[i] >> 16) & 0xFF) * GREY_WEIGHT;
  551.  
  552.                 /* difference calculation */
  553.  
  554.                 diff = grey - grey2; 
  555.         if(diff<0) diff = -diff;
  556.  
  557.                 /* check for better match */
  558.  
  559.                 if(diff < close_diff)
  560.                 {
  561.                         close_diff      = diff;
  562.                         close_rgb.value = i;
  563.                         close_rgb.red   = (s->palette[i] >> 16) & 0xFF;
  564.                         close_rgb.green = close_rgb.red;
  565.                         close_rgb.blue  = close_rgb.red;
  566.  
  567.                         /* short cut for extact match */
  568.  
  569.                         if(diff == 0) i=s->cols;
  570.                 }
  571.         }
  572.  
  573.         /* cache value and return closest colour index & rgb info */
  574.  
  575.         cache[index] = close_rgb;
  576.  
  577.         return(&close_rgb);
  578. }
  579.  
  580. /*
  581.  * linear 8 bit grey or inverted linear 8 bit grey
  582.  */
  583.  
  584. static pix_str *closest_rgb_grey8(spr_info_str *s, pix_str *rgb)
  585. {
  586.     static pix_str close_rgb;
  587.     REGISTER int r,g,b;
  588.              int index;
  589.     
  590.         r = rgb->red;
  591.     g = rgb->green;
  592.     b = rgb->blue;
  593.     
  594.         RANGE_RGB(r);
  595.         RANGE_RGB(g);
  596.         RANGE_RGB(b);
  597.  
  598.         index = (r * RED_WEIGHT   +
  599.                  g * GREEN_WEIGHT +
  600.                  b * BLUE_WEIGHT) >> GREY_SHIFT;
  601.  
  602.     if((s->palette[0] & 0xFFFFFF00) != 0)
  603.         index = 255-index;
  604.  
  605.         close_rgb.value = index;
  606.     close_rgb.red   = (s->palette[index] >> 16) & 0xFF;
  607.         close_rgb.green = close_rgb.red;
  608.         close_rgb.blue  = close_rgb.red;
  609.  
  610.     return(&close_rgb);
  611. }
  612.  
  613. /*
  614.  * 8 bit standard desktop palette
  615.  * finds best match from nearest +/- r,g,b and tint combinations
  616.  */
  617.  
  618. static pix_str *closest_rgb_desk8(spr_info_str *s, pix_str *rgb)
  619. {
  620.     uint         palette[3*3*3*4];
  621.     uint         value[3*3*3*4];
  622.         int          index;
  623.         REGISTER int cols = 0;
  624.     REGISTER int r,g,b;
  625.     REGISTER int r2,g2,b2,t;
  626.     pix_str      rgb2 = *rgb;
  627.     pix_str     *close_rgb;
  628.  
  629.     /* check for value in the cache */
  630.  
  631.         RANGE_RGB(rgb2.red);
  632.         RANGE_RGB(rgb2.green);
  633.         RANGE_RGB(rgb2.blue);
  634.  
  635.     if((close_rgb = check_cache(s, &rgb2, &index))!=0)
  636.         return(close_rgb);
  637.  
  638.         r = rgb2.red   & 0xC0;
  639.         g = rgb2.green & 0xC0;
  640.         b = rgb2.blue  & 0xC0;
  641.  
  642.         for(b2=b-0x40; b2<=b+0x40; b2+=0x40)
  643.         {
  644.         if(b2>=0 && b2<0x100)
  645.             for(g2=g-0x40; g2<=g+0x40; g2+=0x40)
  646.             {
  647.             if(g2>=0 && g2<0x100)
  648.                 for(r2=r-0x40; r2<=r+0x40; r2+=0x40)
  649.         {
  650.                 if(r2>=0 && r2<0x100)
  651.             for(t=0; t<4; t++)
  652.             {
  653.             palette[cols]  = ((b2+(t<<4)) << 24) |
  654.                      ((g2+(t<<4)) << 16) |
  655.                      ((r2+(t<<4)) << 8);
  656.             palette[cols] |= (palette[cols] >> 4);
  657.             value[cols++]  =  (b2       & 0x80) |
  658.                      ((g2 >> 1) & 0x60) |
  659.                      ((r2 >> 3) & 0x10) |
  660.                      ((b2 >> 3) & 0x08) |
  661.                      ((r2 >> 4) & 0x04) |
  662.                                            t;;
  663.             }
  664.         }
  665.         }
  666.     }
  667.  
  668.     /* call core routine */
  669.  
  670.     close_rgb = closest_rgb_core(rgb, palette, cols);
  671.  
  672.         /* map returned value to calculated colour number */
  673.  
  674.         close_rgb->value = value[close_rgb->value];
  675.  
  676.         /* cache value and return closest colour index & rgb info */
  677.  
  678.         cache[index] = *close_rgb;
  679.  
  680.         return(close_rgb);
  681. }
  682.  
  683. /*
  684.  * palette that fully span colour cube
  685.  */
  686.  
  687. static pix_str *closest_rgb_cube(spr_info_str *s, pix_str *rgb)
  688. {
  689.     uint         palette[256];
  690.     uint         value[256];
  691.         int          index;
  692.         REGISTER int i;
  693.         REGISTER int cols = 0;
  694.     REGISTER int r,g,b;
  695.     pix_str      rgb2 = *rgb;
  696.     pix_str     *close_rgb;
  697.  
  698.     /* check for value in the cache */
  699.  
  700.         RANGE_RGB(rgb2.red);
  701.         RANGE_RGB(rgb2.green);
  702.         RANGE_RGB(rgb2.blue);
  703.  
  704.     if((close_rgb = check_cache(s, &rgb2, &index))!=0)
  705.         return(close_rgb);
  706.  
  707.     for(i=0; i<s->cols; i++)
  708.     {
  709.         SPLIT_RGB(s->palette[i]);
  710.  
  711.         if((r-rgb2.red)<0x80   && (r-rgb2.red)>-0x80   &&
  712.            (g-rgb2.green)<0x80 && (g-rgb2.green)>-0x80 &&
  713.            (b-rgb2.blue)<0x80  && (b-rgb2.blue)>-0x80)
  714.         {
  715.             palette[cols]  = s->palette[i];
  716.             value[cols++]  = i;
  717.         }
  718.     }
  719.     
  720.     /* call core routine */
  721.  
  722.     close_rgb = closest_rgb_core(rgb, palette, cols);
  723.  
  724.         /* map returned value to calculated colour number */
  725.  
  726.         close_rgb->value = value[close_rgb->value];
  727.  
  728.         /* cache value and return closest colour index & rgb info */
  729.  
  730.         cache[index] = *close_rgb;
  731.  
  732.         return(close_rgb);
  733. }
  734.  
  735. /*
  736.  * work out palette type and select best closest_rgb function
  737.  */
  738.  
  739. void closest_rgb_func(spr_info_str *s)
  740. {
  741.     BOOL grey, grey8, igrey8;
  742.     uint rgb, r,g,b;
  743.     uint span;
  744.     int  i;
  745.  
  746.     if(s->bpp == 24)
  747.     {
  748.         s->closest_rgb = closest_rgb_24;
  749.         return;
  750.     }
  751.     if(s->bpp == 15)
  752.     {
  753.         s->closest_rgb = closest_rgb_15;
  754.         return;
  755.     }
  756.  
  757.     if(s->has_palette == 0)
  758.     {
  759.         fprintf(stderr,"sprite must have a palette for closest_rgb\n");
  760.         exit(1);
  761.     }
  762.  
  763.     if(s->bpp==1 && (((s->palette[0] & 0xFFFFFF00)==0x00000000 &&
  764.                           (s->palette[1] & 0xFFFFFF00)==0xFFFFFF00) ||
  765.                          ((s->palette[0] & 0xFFFFFF00)==0xFFFFFF00 &&
  766.                           (s->palette[1] & 0xFFFFFF00)==0x00000000)))
  767.     {
  768.         s->closest_rgb = closest_rgb_1;
  769.         return;
  770.     }
  771.  
  772.     grey = grey8 = igrey8 = TRUE;
  773.     span = 0;
  774.  
  775.     for(i=0; i<s->cols; i++)
  776.     {
  777.                 rgb = s->palette[i] & 0xFFFFFF00;
  778.  
  779.         if(grey)
  780.         {
  781.             SPLIT_RGB(rgb);
  782.  
  783.             if(r!=g || g!=b)
  784.             {
  785.                 grey   = FALSE;
  786.                 grey8  = FALSE;
  787.                 igrey8 = FALSE;
  788.             }
  789.             else
  790.             {
  791.                 if(r != i)       grey8 = FALSE;
  792.                 if(r != (255-i)) igrey8 = FALSE;
  793.             }
  794.         }
  795.  
  796.         if(rgb == 0x00000000) span |= 0x01;
  797.         if(rgb == 0x0000FF00) span |= 0x02;
  798.         if(rgb == 0x00FF0000) span |= 0x04;
  799.         if(rgb == 0x00FFFF00) span |= 0x08;
  800.         if(rgb == 0xFF000000) span |= 0x10;
  801.         if(rgb == 0xFF00FF00) span |= 0x20;
  802.         if(rgb == 0xFFFF0000) span |= 0x40;
  803.         if(rgb == 0xFFFFFF00) span |= 0x80;
  804.     }
  805.  
  806.     if(grey8 || igrey8)
  807.     {
  808.         s->closest_rgb = closest_rgb_grey8;
  809.         return;
  810.     }
  811.     if(grey)
  812.     {
  813.         s->closest_rgb = closest_rgb_grey;
  814.         return;
  815.     }
  816.  
  817.     if(s->bpp == 8)
  818.     {
  819.         uint palette[256];
  820.         palette256(palette);
  821.         if(memcmp(s->palette, palette, 4*256)==0)
  822.         {
  823.             s->closest_rgb = closest_rgb_desk8;
  824.             return;
  825.         }
  826.     }
  827.  
  828.     if(span == 0xFF)
  829.     {
  830.         s->closest_rgb = closest_rgb_cube;
  831.         return;
  832.     }
  833.  
  834.     /* use general routine */
  835.  
  836.     s->closest_rgb = closest_rgb_gen;
  837. }
  838.