home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / System / Mesa-3.1 / src / AOS / palettes.c < prev    next >
C/C++ Source or Header  |  1999-09-23  |  24KB  |  772 lines

  1. /*
  2.  * $Id: $
  3.  */
  4.  
  5. /*
  6.  * Mesa 3-D graphics library
  7.  * Version:  3.1
  8.  * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
  9.  *
  10.  * This library is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU Library General Public
  12.  * License as published by the Free Software Foundation; either
  13.  * version 2 of the License, or (at your option) any later version.
  14.  *
  15.  * This library is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18.  * Library General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU Library General Public
  21.  * License along with this library; if not, write to the Free
  22.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  */
  24.  
  25. #include <math.h>
  26. #include <stddef.h>
  27.  
  28. #define    NO_CONTEXT_AVAILABLE
  29. #include <AOS/amigamesa.h>
  30. #include <graphics/view.h>
  31.  
  32. #include "palettes/palettes.c"                            /* pre-defined palettes */
  33. #include "palettes/error.c"                            /* match-error tables */
  34. #include "palettes/remap.c"                            /* remap-tables */
  35. #include "palettes/clamps.c"                            /* clamping-tables */
  36.  
  37. #define    MATCH_ERROR
  38. #define    REAL_HPCR
  39. //#undef    ASM_CODE
  40. #undef    MATCH_6BITS
  41. #undef    REVISIT_PALETTE
  42. #undef    REVISIT_YCrCb
  43.  
  44. /*****************************************************************************/
  45. /*                               modelling                     */
  46. /*****************************************************************************/
  47.  
  48. /* allocate all pens for a given max-number of colors into a given list */
  49. static BOOL AllocColors(struct ColorEntry *Cols, GLshort Number, struct Screen *Screen)
  50. {
  51.   register LONG pen;
  52.   register BOOL fail = GL_TRUE;
  53.   register struct ColorMap *ColorMap = Screen->ViewPort.ColorMap;
  54.   ULONG ColTab[3];
  55.   GLshort fill = Number;
  56. #ifdef    REVISIT_PALETTE
  57.   ULONG ColorTable[256][3];
  58.   GLshort j = Number, k = 256;
  59. #endif
  60.  
  61.   do {
  62.     GLshort newNumber = remap[Number];
  63.  
  64.     if ((pen = ObtainBestPen(ColorMap, c8toc32(Cols[newNumber].orgEntry.r),
  65.                        c8toc32(Cols[newNumber].orgEntry.g),
  66.                        c8toc32(Cols[newNumber].orgEntry.b),
  67.                        OBP_Precision, PRECISION_EXACT, TAG_DONE)) == -1)
  68.       fail = GL_FALSE;
  69.     else {
  70.       Cols[newNumber].PenNo = pen;
  71.       GetRGB32(ColorMap, pen, 1, ColTab);
  72.       Cols[newNumber].mapEntry.r = ColTab[0] >> 24;
  73.       Cols[newNumber].mapEntry.g = ColTab[1] >> 24;
  74.       Cols[newNumber].mapEntry.b = ColTab[2] >> 24;
  75.     }
  76.   } while (--Number >= 0);                            /* Number is the max-value, not including! */
  77.  
  78. #ifdef    REVISIT_PALETTE
  79.   GetRGB32(ColorMap, 0, 256, ColorTable[0]);
  80.  
  81.   while (--k >= 0) {
  82.     GLshort newNumber = remap[k];
  83.     register GLshort i = j;
  84.  
  85. #ifndef    REVISIT_YCrCb
  86.     register GLshort match = 0x7FFF, max = 0;
  87.  
  88.     for (pen = 0; i >= 0; i--) {
  89.       register GLshort thismatch, thismax;
  90.  
  91. #ifdef    MATCH_ERROR
  92.       register GLshort sum;
  93.  
  94.       if ((thismatch = (GLshort)((ColorTable[i][0] >> 24)) - (GLshort)Cols[newNumber].orgEntry.r) < 0)
  95.     thismatch = -thismatch;
  96.       thismax = thismatch;
  97.       if ((sum = (GLshort)((ColorTable[i][1] >> 24)) - (GLshort)Cols[newNumber].orgEntry.g) < 0)
  98.     sum = -sum;
  99.       if (sum > thismax)
  100.         thismax = sum;
  101.       thismatch += sum;
  102.       if ((sum = (GLshort)((ColorTable[i][2] >> 24)) - (GLshort)Cols[newNumber].orgEntry.b) < 0)
  103.     sum = -sum;
  104.       if (!(thismatch += sum)) {
  105.     pen = i;
  106.     break;
  107.       }
  108.       if (sum > thismax)
  109.         thismax = sum;
  110. #else
  111.       register GLshort sum;
  112.  
  113.       sum        = error111[(GLshort)((ColorTable[i][0] >> 24)) - (((GLshort)Cols[newNumber].orgEntry.r) * 4) + 0];
  114.       thismatch  = sum;
  115.       thismax    = sum;
  116.       sum        = error111[(GLshort)((ColorTable[i][1] >> 24)) - (((GLshort)Cols[newNumber].orgEntry.g) * 4) + 1];
  117.       thismatch += sum;
  118.       if (sum > thismax)
  119.         thismax = sum;
  120.       sum        = error111[(GLshort)((ColorTable[i][2] >> 24)) - (((GLshort)Cols[newNumber].orgEntry.b) * 4) + 2];
  121.       if (!(thismatch += sum)) {
  122.     pen = i;
  123.     break;
  124.       }
  125.       if (sum > thismax)
  126.         thismax = sum;
  127. #endif
  128. #else
  129.     /* maybe the best match is to match in YCrCb- not in RGB-space */
  130.     register GLint match = 1000000000, max = 0;
  131.     double Y, Cr, Cb;
  132.  
  133. #define    toY(R, G, B)    ( 0.29900 * R + 0.58700 * G + 0.11400 * B)
  134. #define    toCr(R, G, B)    (-0.16874 * R - 0.33126 * G + 0.50000 * B)
  135. #define    toCb(R, G, B)    ( 0.50000 * R - 0.41869 * G - 0.08131 * B)
  136.  
  137.     Y = toY(Cols[newNumber].orgEntry.r, Cols[newNumber].orgEntry.g, Cols[newNumber].orgEntry.b);
  138.     Cr = toCr(Cols[newNumber].orgEntry.r, Cols[newNumber].orgEntry.g, Cols[newNumber].orgEntry.b);
  139.     Cb = toCb(Cols[newNumber].orgEntry.r, Cols[newNumber].orgEntry.g, Cols[newNumber].orgEntry.b);
  140.  
  141.     for (pen = 0; i >= 0; i--) {
  142.       register double sum;
  143.       register double thismatch, thismax;
  144.  
  145.       if ((thismatch = toY((ColorTable[i][0] >> 24), (ColorTable[i][1] >> 24), (ColorTable[i][2] >> 24)) - Y) < 0)
  146.     thismatch = -thismatch;
  147.       thismax = thismatch;
  148.  
  149.       if ((sum = toCr((ColorTable[i][0] >> 24), (ColorTable[i][1] >> 24), (ColorTable[i][2] >> 24)) - Cr) < 0)
  150.     sum = -sum;
  151.       if (sum > thismax)
  152.         thismax = sum;
  153.       thismatch += sum;
  154.  
  155.       if ((sum = toCb((ColorTable[i][0] >> 24), (ColorTable[i][1] >> 24), (ColorTable[i][2] >> 24)) - Cb) < 0)
  156.     sum = -sum;
  157.       if (!(thismatch += sum)) {
  158.     pen = i;
  159.     break;
  160.       }
  161.       if (sum > thismax)
  162.         thismax = sum;
  163. #endif
  164.  
  165.       /* this is the key for good pen-matching! :^) */
  166.       if (match < (GLint)thismatch)
  167.         continue;
  168.       if (match == (GLint)thismatch) {
  169.         if (max < (GLint)thismax)
  170.           continue;
  171.         /* what to do now? match is equal, max is equal */
  172.         if (max == (GLint)thismax) {
  173.         }
  174.       }
  175.  
  176.       match = (GLint)thismatch;
  177.       max = (GLint)thismax;
  178.       pen = i;
  179.     }
  180.     
  181.     if (pen != Cols[newNumber].PenNo) {
  182.       DEBUGOUT(0, " original: 0x%06x -> old: 0x%06x (%4d/%4d/%4d), new: 0x%06x (%4d/%4d/%4d) -> old: 0x%x, new: 0x%x\n",
  183.            *((ULONG *)&Cols[newNumber].orgEntry) >> 8,
  184.            *((ULONG *)&Cols[newNumber].mapEntry) >> 8,
  185.            Cols[newNumber].mapEntry.r - Cols[newNumber].orgEntry.r,
  186.            Cols[newNumber].mapEntry.g - Cols[newNumber].orgEntry.g,
  187.            Cols[newNumber].mapEntry.b - Cols[newNumber].orgEntry.b,
  188.            ((ColorTable[pen][0] >>  8) & 0x00FF0000) |
  189.            ((ColorTable[pen][1] >> 16) & 0x0000FF00) |
  190.            ((ColorTable[pen][2] >> 24) & 0x000000FF),
  191.            (ColorTable[pen][0] >> 24) - Cols[newNumber].orgEntry.r,
  192.            (ColorTable[pen][1] >> 24) - Cols[newNumber].orgEntry.g,
  193.            (ColorTable[pen][2] >> 24) - Cols[newNumber].orgEntry.b,
  194.            Cols[newNumber].PenNo, pen);
  195. #if 0
  196.       /* lock new key without changing it's value and release old pen */
  197.       ObtainPen(Screen->ViewPort.ColorMap, pen, 0, 0, 0, PENF_NO_SETCOLOR);
  198.       ReleasePen(Screen->ViewPort.ColorMap, Cols[newNumber].PenNo);
  199. #endif
  200.       Cols[newNumber].PenNo = pen;
  201.     }
  202.   }
  203. #endif
  204.  
  205.   /* this is for PenNo-clamping of grey-levels beyond 64 */
  206.   if (fill < 255) {
  207.     do {
  208.       Cols[++fill].PenNo = Cols[fill].PenNo;
  209.     } while (fill <= 255);
  210.   }
  211.  
  212.   return (BOOL) fail;
  213. };
  214.  
  215. /* free all pens for all PaletteModes */
  216. static void FreeColors(struct ColorEntry *Cols, GLshort Number, struct Screen *Screen)
  217. {
  218.   while (--Number >= 0)
  219.     ReleasePen(Screen->ViewPort.ColorMap, Cols[Number].PenNo);
  220. };
  221.  
  222. /*****************************************************************************/
  223. /*                               encoding                     */
  224. /*****************************************************************************/
  225.  
  226. /* match a pen to a RGB */
  227. static inline ULONG Match(register unsigned char R __asm__("d0"),
  228.               register unsigned char G __asm__("d1"),
  229.               register unsigned char B __asm__("d2"),
  230.               register amigaMesaContext amesa __asm__("a0")) {
  231.   register ULONG pen = 0;
  232.  
  233.   /* pen-caching doesn't make sense for dithers, as the
  234.    * random character of the dither-matrice are allmost
  235.    * never the same for neighbourhood-pixels (spans/arrays)
  236.    * only for random jumping pixels (random + random = linear)
  237.    * but that's highly unlikly
  238.    * you can take a look at the cache-performance and verify
  239.    * this statement
  240.    */
  241.   if (TstF(amesa->flags, PALETTE_CACHE)) {
  242. #define    cachedPen    pen
  243.     /* use G as LUT 'cause it has the middle energy */
  244.     if ((cachedPen = *((ULONG *) & amesa->penCache[G]))) {
  245.       cachedPen >>= 8;
  246.       if ((unsigned char)cachedPen == (unsigned char)B) {
  247.     cachedPen >>= 8;
  248.     if ((unsigned char)cachedPen == (unsigned char)R) {
  249.       cachedPen >>= 8;
  250.       return cachedPen;
  251.     }
  252.       }
  253.     }
  254.     cachedPen = ((((R << 8) | B) << 8) | CACHED);
  255.     *((ULONG *) & amesa->penCache[G]) = cachedPen;
  256.   }
  257.  
  258. {
  259.   register GLshort i = amesa->PaletteCols;
  260.   register struct ColorEntry *entries = amesa->Palette + i;
  261. #ifdef    MATCH_ERROR
  262.   register GLshort *errors = (GLshort *)amesa->MatchErrors;
  263. #endif
  264.  
  265.   /* infinite bad start-match */
  266.   register GLshort match = 0x7FFF;
  267.  
  268.   /* pal332-mask:
  269.    * 
  270.    *   0x00 = 0b000 00000
  271.    *   0x20 = 0b001 00000
  272.    *   0x40 = 0b010 00000
  273.    *   0x80 = 0b100 00000
  274.    *   0xA0 = 0b101 00000
  275.    *   0xC0 = 0b110 00000
  276.    *   0xE0 = 0b111 00000
  277.    *  -------------------
  278.    *   0xE0 = 0b111 00000
  279.    * 
  280.    *  if (!(R & (~0xE0)))
  281.    *    entries -= 256 - (((R >> 5) + 1) * 32);
  282.    *    entries += (R >> 5) * 32;
  283.    *  if (!(G & (~0xE0)))
  284.    *    entries -=  32 - (((G >> 5) + 1) *  4);
  285.    *    entries += (G >> 5) *  4;
  286.    *  if (!(B & (~0xC0)))
  287.    *    entries -=   4 - (((B >> 6) + 1) *  1);
  288.    *    entries += (B >> 5) *  1;
  289.    * 
  290.    * pal189-mask:
  291.    *  
  292.    *   0x00 = 0b0000 0000
  293.    *   0x1F = 0b0001 1111
  294.    *   0x3F = 0b0011 1111
  295.    *   0x5F = 0b0101 1111
  296.    *   0x7F = 0b1000 1111
  297.    *   0x9F = 0b1001 1111
  298.    *   0xBF = 0b1011 1111
  299.    *   0xDF = 0b1101 1111
  300.    *   0xFF = 0b1111 1111
  301.    *  -------------------
  302.    *   0xF0 = 0b1111 ????
  303.    * 
  304.    *  if (!(R & (~0xFF)))
  305.    *    entries += ?;
  306.    *
  307.    * palgrey-mask:
  308.    *  
  309.    *   0x00 = 0b000000 00
  310.    *   0x04 = 0b000001 00
  311.    *   0x08 = 0b000010 00
  312.    *   0x0C = 0b000011 00
  313.    *   .... = ........ 00
  314.    *   0xFC = 0b111111 00
  315.    *  -------------------
  316.    *   0xFC = 0b111111 00
  317.    * 
  318.    *  if (!(R & (~0xFC)))
  319.    *    entries -= 64 - (((R >> 2) + 1) *  1);
  320.    *  if (!(G & (~0xFC)))
  321.    *    entries -= 16 - (((G >> 2) + 1) *  1);
  322.    *  if (!(B & (~0xFC)))
  323.    *    entries -=  4 - (((B >> 2) + 1) *  1);
  324.    */
  325.  
  326.   /* find match */
  327.   for (; i >= 0; i--, entries--) {
  328.     register GLshort thismatch;
  329.  
  330. #ifdef    MATCH_ERROR
  331.     if (!(thismatch = errors[(((GLshort)entries->mapEntry.r - (GLshort)R) * 4) + 0] +
  332.               errors[(((GLshort)entries->mapEntry.g - (GLshort)G) * 4) + 1] +
  333.               errors[(((GLshort)entries->mapEntry.b - (GLshort)B) * 4) + 2])) {
  334.       pen = i;
  335.       break;
  336.     }
  337. #else
  338.     register GLshort sum;
  339.  
  340.     if ((thismatch = (GLshort)(entries->mapEntry.r) - (GLshort)R) < 0)
  341.       thismatch = -thismatch;
  342.     if ((sum = (GLshort)(entries->mapEntry.g) - (GLshort)G) < 0)
  343.       sum = -sum;
  344.     thismatch += sum;
  345.     if ((sum = (GLshort)(entries->mapEntry.b) - (GLshort)B) < 0)
  346.       sum = -sum;
  347.     if (!(thismatch += sum)) {
  348.       pen = i;
  349.       break;
  350.     }
  351. #endif
  352.  
  353.     if (match > thismatch) {
  354.       match = thismatch;
  355.       pen = i;
  356.     }
  357.   }
  358. }
  359.  
  360.   pen = (ULONG) (amesa->Palette[pen].PenNo);
  361.   if (amesa->flags & PALETTE_CACHE)
  362.     amesa->penCache[G].PenCch = (unsigned char)(pen);
  363.  
  364.   return pen;
  365. };
  366.  
  367. /*****************************************************************************/
  368.  
  369. ULONG GetPen(register unsigned char R __asm__("d0"),
  370.          register unsigned char G __asm__("d1"),
  371.          register unsigned char B __asm__("d2"),
  372.          register amigaMesaContext amesa __asm__("a0")) {
  373.   /* quick original HPCR-match, looks very dark
  374.    * is not so good without dithering, in the
  375.    * XMesa they talk about a special colormap
  376.    * but I havn't found it
  377.    */
  378. #ifdef    REAL_HPCR
  379.   if (IS_HPCR(amesa->trueColor)) {
  380. #ifndef ASM_CODE
  381.     return amesa->Palette[c24toc8(((GLshort *)amesa->MatchErrors)[(R * 4) + 0],
  382.                   ((GLshort *)amesa->MatchErrors)[(G * 4) + 1],
  383.                   ((GLshort *)amesa->MatchErrors)[(B * 4) + 2])].PenNo;
  384. #else
  385.     __asm__("
  386.     .equ    erroffs,%5
  387.     .equ    paloffs,%4
  388.     .equ    amesa,%3
  389.     .equ    err,a1
  390.     .equ    mask,d3
  391.     .equ    r,%0
  392.     .equ    g,%1
  393.     .equ    b,%2
  394.  
  395.     move%.l    amesa@(erroffs),err        |  amesa->MatchErrors
  396.     moveq    #0xFFFFFFE0,mask
  397.     move%.w    err@(0,r:w:8),r            |  amesa->MatchErrors[R][0]
  398.     and%.w    mask,r                |  amesa->MatchErrors[R][0] & 0xE0
  399.     move%.w    err@(2,g:w:8),g            |  amesa->MatchErrors[G][1]
  400.     and%.w    mask,g                |  amesa->MatchErrors[G][1] & 0xE0
  401.     move%.w    err@(4,b:w:8),b            |  amesa->MatchErrors[B][2]
  402.     and%.w    mask,b                |  amesa->MatchErrors[B][2] & 0xE0
  403.     lsr%.w    #3,g                | (amesa->MatchErrors[G][1] & 0xE0) >> 3
  404.     lsr%.w    #6,b                | (amesa->MatchErrors[B][2] & 0xE0) >> 6
  405.     or%.w    g,r
  406.     or%.w    b,r
  407.     move%.b    amesa@(paloffs+9,r:w:8),r"
  408.     : "=d" (R)
  409.     : "d" (R)
  410.     , "d" (G)
  411.     , "d" (B)
  412.     , "a" (amesa)
  413.     , "i" (117)    /* offsetof(amesa, Palette) doesn't work here ATTENTION if it changes */
  414.     , "i" (2158)    /* offsetof(amesa, MatchErrors) doesn't work here ATTENTION if it changes */
  415.     : "d3", "a1", "cc");
  416.     return R;
  417. #endif
  418.   }
  419. #endif
  420.  
  421.   /* every grey-value we can compute does really exists
  422.    * in the grey-map so the following transformation is
  423.    * allways the same result as if we try to match
  424.    * (the match was done in AllocCMap)
  425.    * take a look at "palettes/quickgrey.c" why I choose
  426.    * this approximated (and on the first view) totally
  427.    * wrong function
  428.    * the function does produce levels beyond 64 (69,...)
  429.    * but for grey we must clamp negative values so we can
  430.    * put the value for palette[64].PenNo into the higher
  431.    * (unused) PenNos
  432.    */
  433.   if (IS_GREY(amesa->trueColor)) {
  434. #ifndef ASM_CODE
  435.     return amesa->Palette[((R << 5) + (G << 6) + (G << 5) + (G << 1) + (B << 3) + B) >> 9].PenNo;    /* aprox. to shifts */
  436. #else
  437.     __asm__("
  438.     .equ    paloffs,%4
  439.     .equ    amesa,%3
  440.     .equ    r,%0
  441.     .equ    g,%1
  442.     .equ    b,%2
  443.  
  444.     lsl%.w    #5,r        |                                                  (r << 5)
  445.     add%.w    b,r        |                                              b + (r << 5)
  446.     lsl%.w    #3,b        |                                   (b << 3)
  447.     add%.w    b,r        |                                   (b << 3) + b + (r << 5)
  448.     add%.w    g,g        |                        (g << 1)
  449.     add%.w    g,r        |                        (g << 1) + (b << 3) + b + (r << 5)
  450.     lsl%.w    #4,g        |             (g << 5)
  451.     add%.w    g,r        |             (g << 5) + (g << 1) + (b << 3) + b + (r << 5)
  452.     add%.w    g,g        |  (g << 6)
  453.     add%.w    g,r        |  (g << 6) + (g << 5) + (g << 1) + (b << 3) + b + (r << 5)
  454.     lsr%.w    #8,r        | ((g << 6) + (g << 5) + (g << 1) + (b << 3) + b + (r << 5)) >> 9
  455.     lsr%.w    #1,r
  456.     move%.b    amesa@(paloffs+9,r:w:8),r"
  457.     : "=d" (R)
  458.     : "d" (R)
  459.     , "d" (G)
  460.     , "d" (B)
  461.     , "a" (amesa)
  462.     , "i" (117)    /* offsetof(amesa, Palette) doesn't work here ATTENTION if it changes */
  463.     : "cc");
  464.     return R;
  465. #endif
  466.   }
  467.  
  468.   /* on most graphics-cards there are only 6bits per palette-entry
  469.    * so the error produced by this shouldn't be too high but make the
  470.    * matching faster (hopefull, not tested yet)
  471.    */
  472. #ifdef    MATCH_6BITS
  473.   R &= 0xFC;
  474.   G &= 0xFC;
  475.   B &= 0xFC;
  476. #endif
  477.  
  478.   return Match(R, G, B, amesa);
  479. };
  480.  
  481. /*****************************************************************************/
  482.  
  483. /* red, green and blue have different modification-values
  484.  * max red is -15/16
  485.  * max green is -15/16
  486.  * max blue is -30/32
  487.  * max alpha is 0 )alpga exists only for alignment reasons)
  488.  *
  489.  * generation:
  490.  *  r = ?
  491.  *  g = -r + 1;
  492.  *  b = 
  493.  */
  494. static const GLshort DMatrix[16][2][4] = {
  495.   { { 16,-11,  6,  0}, {-15, 12, -4,  0} },
  496.   { { -4, 15,-18,  0}, {  5,-14, 20,  0} },
  497.   { {  1, -7, 26,  0}, {  0,  8,-24,  0} },
  498.   { {-11,  3, 14,  0}, { 12, -2, 16,  0} },
  499.   { { 14, -8,  2,  0}, {-13,  9,  0,  0} },
  500.   { { -6, 14,-22,  0}, {  7,-13, 24,  0} },
  501.   { {  3, -4, 30,  0}, { -2,  5,-28,  0} },
  502.   { { -9,  2,-10,  0}, { 10, -1, 12,  0} },
  503.   { { 15,-10,  8,  0}, {-14, 11, -6,  0} },
  504.   { { -5, 16,-16,  0}, {  6,-15, 18,  0} },
  505.   { {  2, -6, 28,  0}, { -1,  7,-26,  0} },
  506.   { {-10,  4,-12,  0}, { 11, -3, 14,  0} },
  507.   { { 13, -9,  4,  0}, {-12, 10, -2,  0} },
  508.   { { -7, 13,-20,  0}, {  8,-12, 22,  0} },
  509.   { {  4, -5, 32,  0}, { -3,  6,-30,  0} },
  510.   { { -8,  1,  8,  0}, {  9,  0, 10,  0} },
  511. };
  512.  
  513. #define    DITHER_APPROX(r, g, b, x, y) {            \
  514.   x &= 0xF;                        \
  515.   y &= 0x1;                        \
  516.                             \
  517.   r = clampFF[(GLshort)r + DMatrix[x][y][0] + 32];    \
  518.   g = clampFF[(GLshort)g + DMatrix[x][y][1] + 32];    \
  519.   b = clampFF[(GLshort)b + DMatrix[x][y][2] + 32];    \
  520. }
  521.  
  522. ULONG GetPenDithered(register unsigned char R __asm__("d0"),
  523.              register unsigned char G __asm__("d1"),
  524.              register unsigned char B __asm__("d2"),
  525.              register amigaMesaContext amesa __asm__("a0"),
  526.              register unsigned char X __asm__("d3"),    /* as the ditherkernel doesn't exceed 2^8    */
  527.              register unsigned char Y __asm__("d4")) {    /* we can safe shrink the ccordinates to uc    */
  528.   /* quick original HPCR-match, looks very dark
  529.    * but is fast and looks considerable better
  530.    * than shifting or matching, in the
  531.    * XMesa they talk about a special colormap
  532.    * but I havn't found it
  533.    */
  534. #ifdef    REAL_HPCR
  535.   if (IS_HPCR(amesa->trueColor)) {
  536. #ifndef ASM_CODE
  537.     X &= 0xF;
  538.     Y &= 0x1;
  539.     return amesa->Palette[c24toc8(((GLshort *)amesa->MatchErrors)[(R * 4) + 0] + DMatrix[X][Y][0],
  540.                   ((GLshort *)amesa->MatchErrors)[(G * 4) + 1] + DMatrix[X][Y][1],
  541.                   ((GLshort *)amesa->MatchErrors)[(B * 4) + 2] + DMatrix[X][Y][2])].PenNo;
  542. #else
  543.     __asm__("
  544.     .equ    y,%8
  545.     .equ    x,%7
  546.     .equ    mat,%6
  547.     .equ    erroffs,%5
  548.     .equ    paloffs,%4
  549.     .equ    amesa,%3
  550.     .equ    err,a1
  551.     .equ    mask,d3
  552.     .equ    r,%0
  553.     .equ    g,%1
  554.     .equ    b,%2
  555.  
  556.     and%.w    #0x000F,x            | X & 0xF
  557.     and%.w    #0x0001,y            | Y & 0x1
  558.     add%.w    x,x
  559.     or%.w    y,x
  560.     move%.l    amesa@(erroffs),err        |  amesa->MatchErrors
  561.     moveq    #0xFFFFFFE0,mask
  562.     move%.w    err@(0,r:w:8),r            |  amesa->MatchErrors[R][0]
  563.     add%.w    mat@(0,x:w:8),r            | DMatrix[X][Y][0]
  564.     and%.w    mask,r                |  amesa->MatchErrors[R][0] & 0xE0
  565.     move%.w    err@(2,g:w:8),g            |  amesa->MatchErrors[G][1]
  566.     add%.w    mat@(1,x:w:8),g            | DMatrix[X][Y][1]
  567.     and%.w    mask,g                |  amesa->MatchErrors[G][1] & 0xE0
  568.     move%.w    err@(4,b:w:8),b            |  amesa->MatchErrors[B][2]
  569.     add%.w    mat@(2,x:w:8),b            | DMatrix[X][Y][2]
  570.     and%.w    mask,b                |  amesa->MatchErrors[B][2] & 0xE0
  571.     lsr%.w    #3,g                | (amesa->MatchErrors[G][1] & 0xE0) >> 3
  572.     lsr%.w    #6,b                | (amesa->MatchErrors[B][2] & 0xE0)>> 6
  573.     or%.w    g,r
  574.     or%.w    b,r
  575.     move%.b    amesa@(paloffs+9,r:w:8),r"
  576.     : "=d" (R)
  577.     : "d" (R)
  578.     , "d" (G)
  579.     , "d" (B)
  580.     , "a" (amesa)
  581.     , "i" (117)    /* offsetof(amesa, Palette) doesn't work here ATTENTION if it changes */
  582.     , "i" (2158)    /* offsetof(amesa, MatchErrors) doesn't work here ATTENTION if it changes */
  583.     , "a" (DMatrix)
  584.     , "d" (X)
  585.     , "d" (Y)
  586.     : "a1", "cc");
  587.     return R;
  588. #endif
  589.   }
  590. #endif
  591.  
  592.   /* apply the HPCR-dither-kernel as if it is a
  593.    * ordered dither-matrix, gives good results
  594.    */
  595.   DITHER_APPROX(R, G, B, X, Y);
  596.  
  597.   /* every grey-value we can compute does really exists
  598.    * in the grey-map so the following transformation is
  599.    * allways the same result as if we try to match
  600.    * (the match was done in AllocCMap)
  601.    * take a look at "palettes/quickgrey.c" why I choose
  602.    * this approximated (and on the first view) totally
  603.    * wrong function
  604.    * the function does produce levels beyond 64 (69,...)
  605.    * but for grey we must clamp negative values so we can
  606.    * put the value for palette[64].PenNo into the higher
  607.    * (unused) PenNos
  608.    */
  609.   if (IS_GREY(amesa->trueColor)) {
  610. #ifndef ASM_CODE
  611.     return amesa->Palette[((R << 5) + (G << 6) + (G << 5) + (G << 1) + (B << 3) + B) >> 9].PenNo;    /* aprox. to shifts */
  612. #else
  613.     __asm__("
  614.     .equ    paloffs,%4
  615.     .equ    amesa,%3
  616.     .equ    pal,%3
  617.     .equ    r,%0
  618.     .equ    g,%1
  619.     .equ    b,%2
  620.  
  621.     lsl%.w    #5,r        |                                                  (r << 5)
  622.     add%.w    b,r        |                                              b + (r << 5)
  623.     lsl%.w    #3,b        |                                   (b << 3)
  624.     add%.w    b,r        |                                   (b << 3) + b + (r << 5)
  625.     add%.w    g,g        |                        (g << 1)
  626.     add%.w    g,r        |                        (g << 1) + (b << 3) + b + (r << 5)
  627.     lsl%.w    #4,g        |             (g << 5)
  628.     add%.w    g,r        |             (g << 5) + (g << 1) + (b << 3) + b + (r << 5)
  629.     add%.w    g,g        |  (g << 6)
  630.     add%.w    g,r        |  (g << 6) + (g << 5) + (g << 1) + (b << 3) + b + (r << 5)
  631.     lsr%.w    #8,r        | ((g << 6) + (g << 5) + (g << 1) + (b << 3) + b + (r << 5)) >> 9
  632.     lsr%.w    #1,r
  633.     move%.b    amesa@(paloffs+9,r:w:8),r"
  634.     : "=d" (R)
  635.     : "d" (R)
  636.     , "d" (G)
  637.     , "d" (B)
  638.     , "a" (amesa)
  639.     , "i" (117)    /* offsetof(amesa, Palette) doesn't work here ATTENTION if it changes */
  640.     : "cc");
  641.     return R;
  642. #endif
  643.   }
  644.  
  645.   /* on most graphics-cards there are only 6bits per palette-entry
  646.    * so the error produced by this shouldn't be too high but make the
  647.    * matching faster (hopefull, not tested yet)
  648.    */
  649. #ifdef    MATCH_6BITS
  650.   R &= 0xFC;
  651.   G &= 0xFC;
  652.   B &= 0xFC;
  653. #endif
  654.  
  655.   return Match(R, G, B, amesa);
  656. };
  657.  
  658. /*****************************************************************************/
  659. /*                               preparing                     */
  660. /*****************************************************************************/
  661.  
  662. /* calls AllocColors depend of the PaletteMode */
  663. void AllocCMap(amigaMesaContext amesa, struct Screen *Scr)
  664. {
  665.   DEBUGOUT(1, "AllocCMap(0x%08x, 0x%08x)\n", amesa, Scr);
  666.  
  667.   /* clear pen-cache */
  668.   if (TstF(amesa->flags, PALETTE_CACHE))
  669.     bzero(amesa->penCache, sizeof(amesa->penCache));
  670.  
  671.   /* clear and refill palette */
  672.   if (IS_WEIGHTED(amesa->trueColor)) {
  673.     amesa->PaletteCols = palNumCols - 1;
  674.     amesa->MatchErrors = &error111[ERROR_RANGE / 2][0];
  675.  
  676.     CopyMem(Palette, amesa->Palette, palNumCols * sizeof(struct ColorEntry));
  677.   }
  678.   else if (IS_GREY(amesa->trueColor)) {
  679.     amesa->PaletteCols = palNumColsGrey - 1;
  680.     amesa->MatchErrors = &errorRGB[ERROR_RANGE / 2][0];
  681.  
  682.     CopyMem(PaletteGrey, amesa->Palette, palNumColsGrey * sizeof(struct ColorEntry));
  683.   }
  684.   else if (IS_HPCR(amesa->trueColor)) {
  685.     amesa->PaletteCols = palNumColsHPCR - 1;
  686. #ifdef    REAL_HPCR
  687.     amesa->MatchErrors = &errorHPCR[ERROR_RANGE / 2][0];
  688. #else
  689.     amesa->MatchErrors = &error111[ERROR_RANGE / 2][0];
  690. #endif
  691.  
  692. #ifdef    REAL_HPCR
  693.     CopyMem(Palette332, amesa->Palette, palNumCols * sizeof(struct ColorEntry));
  694. #else
  695.     CopyMem(PaletteHPCR, amesa->Palette, palNumCols * sizeof(struct ColorEntry));
  696. #endif
  697.   }
  698.   else {
  699.     amesa->PaletteCols = palNumCols332 - 1;
  700.     amesa->MatchErrors = &error565[ERROR_RANGE / 2][0];
  701.  
  702.     CopyMem(Palette332, amesa->Palette, palNumCols332 * sizeof(struct ColorEntry));
  703.   }
  704.  
  705.   AllocColors(amesa->Palette, amesa->PaletteCols, Scr);
  706. #ifdef    AOS_WARP3D
  707.   if (amesa->TDdriver) {
  708.     W3D_Color *TDpalette = &amesa->TDdriver->Palette;
  709.     struct ColorEntry *palette = amesa->Palette;
  710.     short int i = 256;
  711.     
  712.     while (--i >= 0) {
  713.       TDpalette->r = (W3D_Float)palette->orgEntry.r;
  714.       TDpalette->g = (W3D_Float)palette->orgEntry.g;
  715.       TDpalette->b = (W3D_Float)palette->orgEntry.b;
  716.       TDpalette->a = (W3D_Float)                0.0;
  717.       TDpalette++;
  718.         palette++;
  719.     }
  720.   }
  721. #endif
  722. };
  723.  
  724. /* calls FreeColors depend of the PaletteMode */
  725. void FreeCMap(amigaMesaContext amesa, struct Screen *Scr)
  726. {
  727.   DEBUGOUT(1, "FreeCMap(0x%08x, 0x%08x)\n", amesa, Scr);
  728.  
  729.   FreeColors(amesa->Palette, amesa->PaletteCols + 1, Scr);
  730. };
  731.  
  732. void RethinkCMap(amigaMesaContext amesa)
  733. {
  734.   GLshort index = 256;
  735.   GLuint *ItoP, *PtoI;
  736.  
  737.   DEBUGOUT(1, "RethinkCMap(0x%08x)\n", amesa);
  738.  
  739.   ItoP = amesa->ItoP;
  740.   PtoI = amesa->PtoI;
  741.  
  742.   while (--index >= 0) {
  743.     GLubyte r, g, b, pen;
  744.  
  745.     r = (GetRGBPLocal(index) >> 24) & 0xFF;
  746.     g = (GetRGBPLocal(index) >> 16) & 0xFF;
  747.     b = (GetRGBPLocal(index) >>  8) & 0xFF;
  748.     pen = PLG_RGBA(amesa, r, g, b);                        /* no dither (index-mode), no shift (gives better quality) */
  749.  
  750.     /* the format of index is RGBP, red|green|blue|pen */
  751.     GetRGBPLocal(index) = (GetRGBPLocal(index) & 0xFFFFFF00) | pen;
  752.     /* the index recovers from index = PtoI[pen] */
  753.     GetIndexLocal(pen) = (GetIndexLocal(pen) & 0xFFFFFF00) | index;
  754.   }
  755. }
  756.  
  757. /* converts one PaletteMode to another on the run */
  758. void ConvertCMap(amigaMesaContext amesa, palMode newColor, struct Screen *Scr)
  759. {
  760.   DEBUGOUT(1, "ConvertCMap(0x%08x, 0x%x, 0x%08x)\n", amesa, newColor, Scr);
  761.  
  762.   if (amesa->trueColor != newColor) {
  763.     amesa->trueColor = newColor;
  764.  
  765.     if (amesa->depth <= 8) {
  766.       FreeCMap(amesa, Scr);
  767.       AllocCMap(amesa, Scr);
  768.       RethinkCMap(amesa);
  769.     }
  770.   }
  771. };
  772.