Advertisement
Zgragselus

BCn Texture Compression

May 18th, 2023
693
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.65 KB | None | 0 0
  1. #ifndef __TEXTURE_COMPRESSOR__H__
  2. #define __TEXTURE_COMPRESSOR__H__
  3.  
  4. #include <math.h>
  5.  
  6. #define BC_ROUNDING_BIAS
  7.  
  8. namespace Engine
  9. {
  10.     class TextureCompressor
  11.     {
  12.     public:
  13.         enum class Format
  14.         {
  15.             BC1 = 0,
  16.             BC2,
  17.             BC3,
  18.             BC4,
  19.             BC5
  20.         };
  21.  
  22.         enum class Quality
  23.         {
  24.             NORMAL = 0,
  25.             HIGH
  26.         };
  27.  
  28.     private:
  29.         static unsigned char mLookUp8To5[256][2];
  30.         static unsigned char mLookUp8To6[256][2];
  31.         static float mMidPoints5[32];
  32.         static float mMidPoints6[64];
  33.         static unsigned char mExpand5[32];
  34.         static unsigned char mExpand6[64];
  35.         static unsigned char mQuantGTab[256 + 16];
  36.         static unsigned char mQuantRBTab[256 + 16];
  37.         static bool mQuantInitialized;
  38.  
  39.         static int Mul8Bit(int a, int b)
  40.         {
  41.             int t = a * b + 128;
  42.             return (t + (t >> 8)) >> 8;
  43.         }
  44.  
  45.         static void From16Bit(unsigned char* out, unsigned short v)
  46.         {
  47.             int r = (v & 0xF800) >> 11;
  48.             int g = (v & 0x07E0) >> 5;
  49.             int b = (v & 0x001F) >> 0;
  50.  
  51.             // Expand to 8-bit via bit replication
  52.             out[0] = (r * 33) >> 2;
  53.             out[1] = (g * 65) >> 4;
  54.             out[2] = (b * 33) >> 2;
  55.             out[3] = 0;
  56.         }
  57.  
  58.         static unsigned short As16Bit(int r, int g, int b)
  59.         {
  60.             return (unsigned short)((Mul8Bit(r, 31) << 11) + (Mul8Bit(g, 63) << 5) + Mul8Bit(b, 31));
  61.         }
  62.  
  63.         static int Lerp13(int a, int b)
  64.         {
  65. #ifdef BC_ROUNDING_BIAS
  66.             return a + Mul8Bit(b - a, 0x55);
  67. #else
  68.             return (2 * a + b) / 3;
  69. #endif
  70.         }
  71.  
  72.         static void Lerp13RGB(unsigned char* out, unsigned char* p1, unsigned char* p2)
  73.         {
  74.             out[0] = (unsigned char)Lerp13(p1[0], p2[0]);
  75.             out[1] = (unsigned char)Lerp13(p1[1], p2[1]);
  76.             out[2] = (unsigned char)Lerp13(p1[2], p2[2]);
  77.         }
  78.  
  79.         static void EvalColors(unsigned char* color, unsigned short c0, unsigned short c1)
  80.         {
  81.             From16Bit(color + 0, c0);
  82.             From16Bit(color + 4, c1);
  83.             Lerp13RGB(color + 8, color + 0, color + 4);
  84.             Lerp13RGB(color + 12, color + 4, color + 0);
  85.         }
  86.  
  87.         static void PrecomputeTables()
  88.         {
  89.             for (int i = 0; i < 32; i++)
  90.             {
  91.                 mExpand5[i] = (i << 3) | (i >> 2);
  92.             }
  93.  
  94.             for (int i = 0; i < 64; i++)
  95.             {
  96.                 mExpand6[i] = (i << 2) | (i >> 4);
  97.             }
  98.  
  99.             for (int i = 0; i < 256 + 16; i++)
  100.             {
  101.                 int v = i - 8 < 0 ? 0 : i - 8 > 255 ? 255 : i - 8;
  102.                 mQuantRBTab[i] = mExpand5[Mul8Bit(v, 31)];
  103.                 mQuantGTab[i] = mExpand6[Mul8Bit(v, 63)];
  104.             }
  105.  
  106.             mQuantInitialized = true;
  107.         }
  108.  
  109.         static void DitherBlock(unsigned char* dest, unsigned char* block)
  110.         {
  111.             if (mQuantInitialized == false)
  112.             {
  113.                 PrecomputeTables();
  114.             }
  115.  
  116.             int err[8];
  117.             int* ep1 = err;
  118.             int* ep2 = err + 4;
  119.             int* et;
  120.  
  121.             // Process channels separately and dither
  122.             for (int channel = 0; channel < 3; channel++)
  123.             {
  124.                 unsigned char* bp = block + channel;
  125.                 unsigned char* dp = dest + channel;
  126.  
  127.                 unsigned char* quant = (channel == 1) ? mQuantGTab + 8 : mQuantRBTab + 8;
  128.  
  129.                 err[0] = err[1] = err[2] = err[3] = err[4] = err[5] = err[6] = err[7] = 0;
  130.  
  131.                 for (int i = 0; i < 4; i++)
  132.                 {
  133.                     dp[0] = quant[bp[0] + ((3 * ep2[1] + 5 * ep2[0]) >> 4)];
  134.                     ep1[0] = bp[0] - dp[0];
  135.                     dp[4] = quant[bp[4] + ((7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]) >> 4)];
  136.                     ep1[1] = bp[4] - dp[4];
  137.                     dp[8] = quant[bp[8] + ((7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]) >> 4)];
  138.                     ep1[2] = bp[8] - dp[8];
  139.                     dp[12] = quant[bp[12] + ((7 * ep1[2] + 5 * ep2[3] + ep2[2]) >> 4)];
  140.                     ep1[3] = bp[12] - dp[12];
  141.                     bp += 16;
  142.                     dp += 16;
  143.  
  144.                     // Swap
  145.                     et = ep1;
  146.                     ep1 = ep2;
  147.                     ep2 = et;
  148.                 }
  149.             }
  150.         }
  151.  
  152.         static unsigned int MatchColorsBlock(unsigned char* block, unsigned char* color, bool dither)
  153.         {
  154.             // Calculate vector for color line
  155.             int dir[3] = { color[0 * 4 + 0] - color[1 * 4 + 0], color[0 * 4 + 1] - color[1 * 4 + 1], color[0 * 4 + 2] - color[1 * 4 + 2] };
  156.  
  157.             // Calculate colors projected on this line
  158.             int stops[4];
  159.             for (int i = 0; i < 4; i++)
  160.             {
  161.                 stops[i] = color[i * 4 + 0] * dir[0] + color[i * 4 + 1] * dir[1] + color[i * 4 + 2] * dir[2];
  162.             }
  163.  
  164.             // Calculate ideal projection of each pixel color on the line
  165.             int dots[16];
  166.             for (int i = 0; i < 16; i++)
  167.             {
  168.                 dots[i] = block[i * 4 + 0] * dir[0] + block[i * 4 + 1] * dir[1] + block[i * 4 + 2] * dir[2];
  169.             }
  170.  
  171.             // At this point all colors are projected on the line, we have just 4 colors linearly on the given line. Determine which is the closest color for given projection
  172.             int c0 = (stops[1] + stops[3]);
  173.             int half = (stops[3] + stops[2]);
  174.             int c3 = (stops[2] + stops[0]);
  175.  
  176.             // Resulting mask
  177.             int mask = 0;
  178.  
  179.             if (!dither)
  180.             {
  181.                 for (int i = 15; i >= 0; i--)
  182.                 {
  183.                     int dot = dots[i] * 2;
  184.                     mask <<= 2;
  185.  
  186.                     if (dot < half)
  187.                     {
  188.                         mask |= (dot < c0) ? 1 : 3;
  189.                     }
  190.                     else
  191.                     {
  192.                         mask |= (dot < c3) ? 2 : 0;
  193.                     }
  194.                 }
  195.             }
  196.             else
  197.             {
  198.                 // Floyd-Steinberg dithering
  199.                 int err[8];
  200.                 int* ep1 = err;
  201.                 int* ep2 = err + 4;
  202.  
  203.                 int* dp = dots;
  204.  
  205.                 c0 <<= 3;
  206.                 half <<= 3;
  207.                 c3 <<= 3;
  208.  
  209.                 for (int i = 0; i < 8; i++)
  210.                 {
  211.                     err[i] = 0;
  212.                 }
  213.  
  214.                 for (int y = 0; y < 4; y++)
  215.                 {
  216.                     int dot, lmask, step;
  217.  
  218.                     dot = (dp[0] << 4) + (3 * ep2[1] + 5 * ep2[0]);
  219.                     if (dot < half)
  220.                         step = (dot < c0) ? 1 : 3;
  221.                     else
  222.                         step = (dot < c3) ? 2 : 0;
  223.                     ep1[0] = dp[0] - stops[step];
  224.                     lmask = step;
  225.  
  226.                     dot = (dp[1] << 4) + (7 * ep1[0] + 3 * ep2[2] + 5 * ep2[1] + ep2[0]);
  227.                     if (dot < half)
  228.                         step = (dot < c0) ? 1 : 3;
  229.                     else
  230.                         step = (dot < c3) ? 2 : 0;
  231.                     ep1[1] = dp[1] - stops[step];
  232.                     lmask |= step << 2;
  233.  
  234.                     dot = (dp[2] << 4) + (7 * ep1[1] + 3 * ep2[3] + 5 * ep2[2] + ep2[1]);
  235.                     if (dot < half)
  236.                         step = (dot < c0) ? 1 : 3;
  237.                     else
  238.                         step = (dot < c3) ? 2 : 0;
  239.                     ep1[2] = dp[2] - stops[step];
  240.                     lmask |= step << 4;
  241.  
  242.                     dot = (dp[3] << 4) + (7 * ep1[2] + 5 * ep2[3] + ep2[2]);
  243.                     if (dot < half)
  244.                         step = (dot < c0) ? 1 : 3;
  245.                     else
  246.                         step = (dot < c3) ? 2 : 0;
  247.                     ep1[3] = dp[3] - stops[step];
  248.                     lmask |= step << 6;
  249.  
  250.                     dp += 4;
  251.                     mask |= lmask << (y * 8);
  252.                     { int* et = ep1; ep1 = ep2; ep2 = et; } // swap
  253.                 }
  254.  
  255.             }
  256.  
  257.             return mask;
  258.         }
  259.  
  260.         static void OptimizeColorBlock(unsigned char* block, unsigned short* max16, unsigned short* min16)
  261.         {
  262.             // Find minimum, maximum and mean color per channel
  263.             int mean_value[3];
  264.             int min_value[3];
  265.             int max_value[3];
  266.  
  267.             for (int channel = 0; channel < 3; channel++)
  268.             {
  269.                 int minv, maxv, muv;
  270.  
  271.                 muv = maxv = minv = block[channel];
  272.                 for (int i = 4; i < 64; i += 4)
  273.                 {
  274.                     muv += block[i + channel];
  275.  
  276.                     if (block[i + channel] < minv)
  277.                     {
  278.                         minv = block[i + channel];
  279.                     }
  280.                     else if (block[i + channel] > maxv)
  281.                     {
  282.                         maxv = block[i + channel];
  283.                     }
  284.                 }
  285.  
  286.                 mean_value[channel] = (muv + 8) >> 4;
  287.                 min_value[channel] = minv;
  288.                 max_value[channel] = maxv;
  289.             }
  290.  
  291.             // Calculate elements of covariance matrix (symmetrical matrix - therefore calculating only bottom triangle of it):
  292.             // R*R G*R B*R
  293.             // R*G G*G B*G
  294.             // R*B G*B B*B
  295.             int covariance_int[6] = { 0 };
  296.             for (int i = 0; i < 16; i++)
  297.             {
  298.                 int r = block[i * 4 + 0] - mean_value[0];
  299.                 int g = block[i * 4 + 1] - mean_value[1];
  300.                 int b = block[i * 4 + 2] - mean_value[2];
  301.  
  302.                 covariance_int[0] += r * r;
  303.                 covariance_int[1] += r * g;
  304.                 covariance_int[2] += r * b;
  305.                 covariance_int[3] += g * g;
  306.                 covariance_int[4] += g * b;
  307.                 covariance_int[5] += b * b;
  308.             }
  309.  
  310.             float covariance_float[6] = { 0.0f };
  311.             for (int i = 0; i < 6; i++)
  312.             {
  313.                 covariance_float[i] = (float)covariance_int[i] / 255.0f;
  314.             }
  315.  
  316.             // Find principal axis based on power interation
  317.             float axis[3] = { (float)(max_value[0] - min_value[0]), (float)(max_value[1] - min_value[1]), (float)(max_value[2] - min_value[2]) };
  318.  
  319.             int ITERATIONS = 1;
  320.             for (int iter = 0; iter < ITERATIONS; iter++)
  321.             {
  322.                 float r = axis[0] * covariance_float[0] + axis[1] * covariance_float[1] + axis[2] * covariance_float[2];
  323.                 float g = axis[0] * covariance_float[1] + axis[1] * covariance_float[3] + axis[2] * covariance_float[4];
  324.                 float b = axis[0] * covariance_float[2] + axis[1] * covariance_float[4] + axis[2] * covariance_float[5];
  325.  
  326.                 axis[0] = r;
  327.                 axis[1] = g;
  328.                 axis[2] = b;
  329.             }
  330.  
  331.             // Calculate magnitude of strongest principal axis component
  332.             float magnitude = fabsf(axis[0]);
  333.             if (fabsf(axis[1]) > magnitude)
  334.             {
  335.                 magnitude = fabsf(axis[1]);
  336.             }
  337.             if (fabsf(axis[2]) > magnitude)
  338.             {
  339.                 magnitude = fabsf(axis[2]);
  340.             }
  341.  
  342.             // Calculate coefficients for principal axis (in integer - range 0 - 1000), if strongest component of principal axis is too weak, default to luminance
  343.             int vector[3] = { 299, 587, 114 };
  344.             if (magnitude >= 4.0f)
  345.             {
  346.                 magnitude = 512.0f / magnitude;
  347.                 vector[0] = (int)(axis[0] * magnitude);
  348.                 vector[1] = (int)(axis[1] * magnitude);
  349.                 vector[2] = (int)(axis[2] * magnitude);
  350.             }
  351.  
  352.             // Pick colors at extreme points
  353.             unsigned char* minp = block;
  354.             unsigned char* maxp = block;
  355.  
  356.             int mind = block[0] * vector[0] + block[1] * vector[1] + block[2] * vector[2];
  357.             int maxd = mind;
  358.             for (int i = 1; i < 16; i++)
  359.             {
  360.                 int dot = block[i * 4 + 0] * vector[0] + block[i * 4 + 1] * vector[1] + block[i * 4 + 2] * vector[2];
  361.  
  362.                 if (dot < mind)
  363.                 {
  364.                     mind = dot;
  365.                     minp = block + i * 4;
  366.                 }
  367.  
  368.                 if (dot > maxd)
  369.                 {
  370.                     maxd = dot;
  371.                     maxp = block + i * 4;
  372.                 }
  373.             }
  374.  
  375.             *min16 = As16Bit(minp[0], minp[1], minp[2]);
  376.             *max16 = As16Bit(maxp[0], maxp[1], maxp[2]);
  377.         }
  378.  
  379.         static unsigned short Quantize5(float x)
  380.         {
  381.             unsigned short q;
  382.             x = x < 0.0f ? 0.0f : x > 1.0f ? 1.0f : x;
  383.             q = (unsigned short)(x * 31.0f);
  384.             q += (x > mMidPoints5[q]);
  385.             return q;
  386.         }
  387.  
  388.         static unsigned short Quantize6(float x)
  389.         {
  390.             unsigned short q;
  391.             x = x < 0.0f ? 0.0f : x > 1.0f ? 1.0f : x;
  392.             q = (unsigned short)(x * 63.0f);
  393.             q += (x > mMidPoints6[q]);
  394.             return q;
  395.         }
  396.  
  397.         static int RefineBlock(unsigned char* block, unsigned short* max16, unsigned short* min16, unsigned int mask)
  398.         {
  399.             int oldmin = *min16;
  400.             int oldmax = *max16;
  401.  
  402.             // Check whether all pixels have same idx
  403.             if ((mask ^ (mask << 2)) < 4)
  404.             {
  405.                 int r = 8;
  406.                 int g = 8;
  407.                 int b = 8;
  408.  
  409.                 for (int i = 0; i < 16; i++)
  410.                 {
  411.                     r += block[i * 4 + 0];
  412.                     g += block[i * 4 + 1];
  413.                     b += block[i * 4 + 2];
  414.                 }
  415.  
  416.                 r >>= 4;
  417.                 g >>= 4;
  418.                 b >>= 4;
  419.  
  420.                 *max16 = (mLookUp8To5[r][0] << 11) | (mLookUp8To6[g][0] << 5) | mLookUp8To5[b][0];
  421.                 *min16 = (mLookUp8To5[r][1] << 11) | (mLookUp8To6[g][1] << 5) | mLookUp8To5[b][1];
  422.             }
  423.             else
  424.             {
  425.                 int at1[3] = { 0, 0, 0 };
  426.                 int at2[3] = { 0, 0, 0 };
  427.                 unsigned int cm = mask;
  428.  
  429.                 int w1table[4] = { 3, 0, 2 ,1 };
  430.                 int prods[4] = { 0x090000, 0x000900, 0x040102, 0x010402 };
  431.  
  432.                 int accumulate = 0;
  433.  
  434.                 for (int i = 0; i < 16; i++, cm >>= 2)
  435.                 {
  436.                     int step = cm & 3;
  437.                     int w1 = w1table[step];
  438.  
  439.                     int r = block[i * 4 + 0];
  440.                     int g = block[i * 4 + 1];
  441.                     int b = block[i * 4 + 2];
  442.  
  443.                     accumulate += prods[step];
  444.  
  445.                     at1[0] += w1 * r;
  446.                     at1[1] += w1 * g;
  447.                     at1[2] += w1 * b;
  448.                     at2[0] += r;
  449.                     at2[1] += g;
  450.                     at2[2] += b;
  451.                 }
  452.  
  453.                 at2[0] = 3 * at2[0] - at1[0];
  454.                 at2[1] = 3 * at2[1] - at1[1];
  455.                 at2[2] = 3 * at2[2] - at1[2];
  456.  
  457.                 int xx = accumulate >> 16;
  458.                 int yy = (accumulate >> 8) & 0xff;
  459.                 int xy = (accumulate >> 0) & 0xff;
  460.  
  461.                 float f = 3.0f / 255.0f / (xx * yy - xy * xy);
  462.  
  463.                 *max16 = Quantize5((at1[0] * yy - at2[0] * xy) * f) << 11;
  464.                 *max16 |= Quantize6((at1[1] * yy - at2[1] * xy) * f) << 5;
  465.                 *max16 |= Quantize5((at1[2] * yy - at2[2] * xy) * f) << 0;
  466.  
  467.                 *min16 = Quantize5((at2[0] * xx - at1[0] * xy) * f) << 11;
  468.                 *min16 |= Quantize6((at2[1] * xx - at1[1] * xy) * f) << 5;
  469.                 *min16 |= Quantize5((at2[2] * xx - at1[2] * xy) * f) << 0;
  470.             }
  471.  
  472.             return (oldmin != *min16) || (oldmax != *max16);
  473.         }
  474.  
  475.         static void CompressColorBlock(unsigned char* dest, unsigned char* src, bool dithering)
  476.         {
  477.             unsigned int mask = 0;
  478.             unsigned short max16 = 0;
  479.             unsigned short min16 = 0;
  480. ;
  481.             unsigned char dblock[16 * 4] = { 0 };
  482.  
  483.             // Check if block is single constant color
  484.             int i = 0;
  485.             for (i = 1; i < 16; i++)
  486.             {
  487.                 //if (((unsigned int*)src)[i] != ((unsigned int*)src)[0])
  488.                 if ((src[i * 4 + 0] != src[0]) ||
  489.                     (src[i * 4 + 1] != src[1]) ||
  490.                     (src[i * 4 + 2] != src[2]))
  491.                 {
  492.                     break;
  493.                 }
  494.             }
  495.  
  496.             if (i == 16)
  497.             {
  498.                 // Constant color, use just that one
  499.                 int r = src[0];
  500.                 int g = src[1];
  501.                 int b = src[2];
  502.  
  503.                 max16 = (mLookUp8To5[r][0] << 11) | (mLookUp8To6[g][0] << 5) | mLookUp8To5[b][0];
  504.                 min16 = (mLookUp8To5[r][1] << 11) | (mLookUp8To6[g][1] << 5) | mLookUp8To5[b][1];
  505.  
  506.                 mask = 0xAAAAAAAA;
  507.             }
  508.             else
  509.             {
  510.                 if (dithering)
  511.                 {
  512.                     DitherBlock(dblock, src);
  513.                 }
  514.  
  515.                 OptimizeColorBlock(dithering ? dblock : src, &max16, &min16);
  516.  
  517.                 if (max16 == min16)
  518.                 {
  519.                     mask = 0x0;
  520.  
  521.                     min16 = 0;
  522.                     max16 = 0;
  523.                 }
  524.                 else
  525.                 {
  526.                     unsigned char color[4 * 4];
  527.                     EvalColors(color, max16, min16);
  528.                     mask = MatchColorsBlock(src, color, dithering);
  529.                 }
  530.  
  531.                 for (i = 0; i < 2; i++)
  532.                 {
  533.                     unsigned int lastmask = mask;
  534.  
  535.                     if (RefineBlock(dithering ? dblock : src, &max16, &min16, mask))
  536.                     {
  537.                         if (max16 == min16)
  538.                         {
  539.                             mask = 0;
  540.                             break;
  541.                         }
  542.                         else
  543.                         {
  544.                             unsigned char color[4 * 4];
  545.                             EvalColors(color, max16, min16);
  546.                             mask = MatchColorsBlock(src, color, dithering);
  547.                         }
  548.                     }
  549.  
  550.                     if (mask == lastmask)
  551.                     {
  552.                         break;
  553.                     }
  554.                 }
  555.             }
  556.  
  557.             if (max16 < min16)
  558.             {
  559.                 unsigned short t = min16;
  560.                 min16 = max16;
  561.                 max16 = t;
  562.  
  563.                 mask ^= 0x55555555;
  564.             }
  565.  
  566.             dest[0] = (unsigned char)(max16);
  567.             dest[1] = (unsigned char)(max16 >> 8);
  568.             dest[2] = (unsigned char)(min16);
  569.             dest[3] = (unsigned char)(min16 >> 8);
  570.             dest[4] = (unsigned char)(mask);
  571.             dest[5] = (unsigned char)(mask >> 8);
  572.             dest[6] = (unsigned char)(mask >> 16);
  573.             dest[7] = (unsigned char)(mask >> 24);
  574.         }
  575.  
  576.         static void SampleAlphaBlock(unsigned char* dest, unsigned char* src, int stride)
  577.         {
  578.             // Resample alpha to be 4 bit per pixel
  579.             for (int i = 0; i < 16; i += 2)
  580.             {
  581.                 int a1 = (src[i * stride]) >> 4;
  582.                 int a2 = (src[(i + 1) * stride]) >> 4;
  583.  
  584.                 unsigned char alpha = (unsigned char)((a1 << 4) + a2);
  585.  
  586.                 dest[i / 2] = alpha;
  587.             }
  588.         }
  589.  
  590.         static void CompressAlphaBlock(unsigned char* dest, unsigned char* src, int stride)
  591.         {
  592.             // Find min and max value
  593.             int minval = src[0];
  594.             int maxval = src[0];
  595.  
  596.             for (int i = 1; i < 16; i++)
  597.             {
  598.                 if (src[i * stride] < minval)
  599.                 {
  600.                     minval = src[i * stride];
  601.                 }
  602.                 else if (src[i * stride] > maxval)
  603.                 {
  604.                     maxval = src[i * stride];
  605.                 }
  606.             }
  607.  
  608.             // Encode min and max value in result
  609.             dest[0] = (unsigned char)maxval;
  610.             dest[1] = (unsigned char)minval;
  611.             dest += 2;
  612.  
  613.             // Determine color indices (mask)
  614.             int dist = maxval - minval;
  615.             int dist2 = dist * 2;
  616.             int dist4 = dist * 4;
  617.  
  618.             int bias = (dist < 8) ? (dist - 1) : (dist / 2 + 2);
  619.             bias -= minval * 7;
  620.  
  621.             int bits = 0;
  622.             int mask = 0;
  623.  
  624.             for (int i = 0; i < 16; i++)
  625.             {
  626.                 int a = src[i * stride] * 7 + bias;
  627.  
  628.                 int ind, t;
  629.  
  630.                 // Select indext (linear scale lerp factor between 0 (val = min) and 7 (val = max)
  631.                 t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t;
  632.                 t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t;
  633.                 ind += (a >= dist);
  634.  
  635.                 // Linear scale into block compression index
  636.                 ind = -ind & 7;
  637.                 ind ^= (2 > ind);
  638.  
  639.                 // Write index
  640.                 mask |= ind << bits;
  641.                 if ((bits += 3) >= 8)
  642.                 {
  643.                     *dest++ = (unsigned char)mask;
  644.                     mask >>= 8;
  645.                     bits -= 8;
  646.                 }
  647.             }
  648.         }
  649.  
  650.     public:
  651.         static void CompressBlock(unsigned char* dest, unsigned char* src, Format format, bool dithering)
  652.         {
  653.             if (format == Format::BC1)
  654.             {
  655.                 CompressColorBlock(dest, src, dithering);
  656.             }
  657.             else if (format == Format::BC2)
  658.             {
  659.                 SampleAlphaBlock(dest, src + 3, 4);
  660.                 CompressColorBlock(dest + 8, src, dithering);
  661.             }
  662.             else if (format == Format::BC3)
  663.             {
  664.                 CompressAlphaBlock(dest, src + 3, 4);
  665.                 CompressColorBlock(dest + 8, src, dithering);
  666.             }
  667.             else if (format == Format::BC4)
  668.             {
  669.                 CompressAlphaBlock(dest, src, 4);
  670.             }
  671.             else if (format == Format::BC5)
  672.             {
  673.                 CompressAlphaBlock(dest, src, 4);
  674.                 CompressAlphaBlock(dest + 8, src + 1, 4);
  675.             }
  676.         }
  677.  
  678.         static void Compress(size_t width, size_t height, unsigned char* dest, unsigned char* src, Format format, size_t stride, bool alpha, bool dithering)
  679.         {
  680.             int channels = alpha ? 4 : 3;
  681.  
  682.             unsigned char* ptr = dest;
  683.  
  684.             for (int y = 0; y < height; y += 4)
  685.             {
  686.                 for (int x = 0; x < width; x += 4)
  687.                 {
  688.                     unsigned char compressed[16 * 4] = { 0 };
  689.                     unsigned char original[16 * 4] = { 0 };
  690.  
  691.                     for (int i = 0; i < 4; i++)
  692.                     {
  693.                         for (int j = 0; j < 4; j++)
  694.                         {
  695.                             original[(i * 4 + j) * 4 + 0] = src[((y + i) * width + (x + j)) * channels + 0];
  696.                             original[(i * 4 + j) * 4 + 1] = src[((y + i) * width + (x + j)) * channels + 1];
  697.                             original[(i * 4 + j) * 4 + 2] = src[((y + i) * width + (x + j)) * channels + 2];
  698.                             original[(i * 4 + j) * 4 + 3] = (alpha ? src[((y + i) * width + (x + j)) * channels + 3] : 255);
  699.                         }
  700.                     }
  701.  
  702.                     CompressBlock(compressed, original, format, dithering);
  703.  
  704.                     if (format == Format::BC1 || format == Format::BC4)
  705.                     {
  706.                         for (int i = 0; i < 8; i++)
  707.                         {
  708.                             (*ptr) = compressed[i];
  709.                             ptr++;
  710.                         }
  711.                     }
  712.                     else
  713.                     {
  714.                         for (int i = 0; i < 16; i++)
  715.                         {
  716.                             (*ptr) = compressed[i];
  717.                             ptr++;
  718.                         }
  719.                     }
  720.                 }
  721.             }
  722.         }
  723.     };
  724. }
  725.  
  726. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement