Advertisement
AboodXD

CompressBC3_cy

Nov 3rd, 2017
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.92 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3.  
  4. cdef list CompressAlphaBlock(bytearray AlphaBlock, bytearray Palette, int Width, int Height, int x, int y):
  5.     cdef list Indices = [0] * 16
  6.  
  7.     cdef int y2, x2, Delta, AlphaDelta
  8.     cdef unsigned int Index, A, i
  9.  
  10.     for y2 in range(4):
  11.         for x2 in range(4):
  12.             if (y + y2) < Height and (x + x2) < Width:
  13.                 Index = 0
  14.                 Delta = 2147483647
  15.  
  16.                 A = AlphaBlock[y2 * 4 + x2]
  17.  
  18.                 for i in range(len(Palette)):
  19.                     if A == Palette[i]:
  20.                         Index = i
  21.                         break
  22.  
  23.                     AlphaDelta = A - Palette[i]
  24.                     AlphaDelta = max(AlphaDelta, -AlphaDelta)
  25.  
  26.                     if AlphaDelta < Delta:
  27.                         Delta = AlphaDelta
  28.                         Index = i
  29.  
  30.                 Indices[y2 * 4 + x2] = Index
  31.  
  32.     return Indices
  33.  
  34. cdef bytearray GetAlphaPalette(unsigned char A0, unsigned char A1):
  35.     cdef bytearray Palette = bytearray(8)
  36.     Palette[0] = A0
  37.     Palette[1] = A1
  38.  
  39.     if A0 > A1:
  40.         Palette[2] = (6 * A0 + 1 * A1) // 7
  41.         Palette[3] = (5 * A0 + 2 * A1) // 7
  42.         Palette[4] = (4 * A0 + 3 * A1) // 7
  43.         Palette[5] = (3 * A0 + 4 * A1) // 7
  44.         Palette[6] = (2 * A0 + 5 * A1) // 7
  45.         Palette[7] = (1 * A0 + 6 * A1) // 7
  46.  
  47.     else:
  48.         Palette[2] = (4 * A0 + 1 * A1) // 5
  49.         Palette[3] = (3 * A0 + 2 * A1) // 5
  50.         Palette[4] = (2 * A0 + 3 * A1) // 5
  51.         Palette[5] = (1 * A0 + 4 * A1) // 5
  52.         Palette[6] = 0
  53.         Palette[7] = 0xFF
  54.  
  55.     return Palette
  56.  
  57.  
  58. cdef list CompressBlock(list ColorBlock, list Palette, int Width, int Height, int x, int y, int ScaleR, int ScaleG, int ScaleB):
  59.     cdef list Indices = [0] * 16
  60.  
  61.     cdef int y2, x2, Delta, RedDelta, GreenDelta, BlueDelta, NewDelta
  62.     cdef unsigned int Index, Color, i
  63.     cdef unsigned char R, G, B, A
  64.  
  65.     for y2 in range(4):
  66.         for x2 in range(4):
  67.             if y + y2 < Height and x + x2 < Width:
  68.                 Index = 0
  69.                 Delta = 2147483647
  70.  
  71.                 Color = ColorBlock[y2 * 4 + x2]
  72.                 R = (Color >> 16) & 0xFF
  73.                 G = (Color >> 8) & 0xFF
  74.                 B = Color & 0xFF
  75.                 A = (Color >> 24) & 0xFF
  76.  
  77.                 for i in range(len(Palette)):
  78.                     if Color == Palette[i]:
  79.                         Index = i
  80.                         break
  81.  
  82.                     RedDelta = R - ((Palette[i] >> 16) & 0xFF)
  83.                     GreenDelta = G - ((Palette[i] >> 8) & 0xFF)
  84.                     BlueDelta = B - (Palette[i] & 0xFF)
  85.  
  86.                     RedDelta = max(RedDelta, -RedDelta)
  87.                     GreenDelta = max(GreenDelta, -GreenDelta)
  88.                     BlueDelta = max(BlueDelta, -BlueDelta)
  89.  
  90.                     NewDelta = RedDelta * ScaleR + GreenDelta * ScaleG + BlueDelta * ScaleB
  91.  
  92.                     if NewDelta < Delta:
  93.                         Delta = NewDelta
  94.                         Index = i
  95.  
  96.                 Indices[y2 * 4 + x2] = Index
  97.  
  98.     return Indices
  99.  
  100. cdef tuple FindMinMax(list Colors):
  101.     cdef unsigned char MaxR = 0
  102.     cdef unsigned char MaxG = 0
  103.     cdef unsigned char MaxB = 0
  104.  
  105.     cdef unsigned char MinR = 255
  106.     cdef unsigned char MinG = 255
  107.     cdef unsigned char MinB = 255
  108.  
  109.     TransparentBlock = True
  110.  
  111.     cdef unsigned int Color
  112.     cdef unsigned char R, G, B, A
  113.  
  114.     for Color in Colors:
  115.         R = (Color >> 16) & 0xFF
  116.         G = (Color >> 8) & 0xFF
  117.         B = Color & 0xFF
  118.         A = (Color >> 24) & 0xFF
  119.  
  120.         if not A:
  121.             continue
  122.  
  123.         TransparentBlock = False
  124.  
  125.         # Max color
  126.         if R > MaxR: MaxR = R
  127.         if G > MaxG: MaxG = G
  128.         if B > MaxB: MaxB = B
  129.  
  130.         # Min color
  131.         if R < MinR: MinR = R
  132.         if G < MinG: MinG = G
  133.         if B < MinB: MinB = B
  134.  
  135.     if TransparentBlock:
  136.         MinR = 0
  137.         MinG = 0
  138.         MinB = 0
  139.  
  140.         MaxR = 0
  141.         MaxG = 0
  142.         MaxB = 0
  143.  
  144.     return MinR, MinG, MinB, MaxR, MaxG, MaxB, TransparentBlock
  145.  
  146. cdef unsigned int ToARGB8(float Red, float Green, float Blue, float Alpha):
  147.     cdef unsigned char R = int(Red * 255)
  148.     cdef unsigned char G = int(Green * 255)
  149.     cdef unsigned char B = int(Blue * 255)
  150.     cdef unsigned char A = int(Alpha * 255)
  151.  
  152.     return (A << 24) | (R << 16) | (G << 8) | B
  153.  
  154. cdef list GetPalette(Color0, Color1):  # using "unsigned short" messes up the colors
  155.     cdef list Palette = [0] * 4
  156.     Palette[0] = ToARGB8(((Color0 >> 11) & 0b11111) / 31, ((Color0 >> 5) & 0b111111) / 63, (Color0 & 0b11111) / 31, 0)
  157.     Palette[1] = ToARGB8(((Color1 >> 11) & 0b11111) / 31, ((Color1 >> 5) & 0b111111) / 63, (Color1 & 0b11111) / 31, 0)
  158.  
  159.     cdef unsigned int R0 = (Palette[0] >> 16) & 0xFF
  160.     cdef unsigned int G0 = (Palette[0] >> 8) & 0xFF
  161.     cdef unsigned int B0 = Palette[0] & 0xFF
  162.     cdef unsigned int R1 = (Palette[1] >> 16) & 0xFF
  163.     cdef unsigned int G1 = (Palette[1] >> 8) & 0xFF
  164.     cdef unsigned int B1 = Palette[1] & 0xFF
  165.  
  166.     Palette[2] = ((2 * R0 // 3 + 1 * R1 // 3) << 16) | ((2 * G0 // 3 + 1 * G1 // 3) << 8) | (2 * B0 // 3 + 1 * B1 // 3)
  167.     Palette[3] = ((1 * R0 // 3 + 2 * R1 // 3) << 16) | ((1 * G0 // 3 + 2 * G1 // 3) << 8) | (1 * B0 // 3 + 2 * B1 // 3)
  168.  
  169.     return Palette
  170.  
  171. cdef unsigned char ToA8(unsigned char Alpha):
  172.     return int(Alpha / 15 * 255)
  173.  
  174. cdef unsigned char ToA4(unsigned char Alpha):
  175.     return int(Alpha / 255 * 15)
  176.  
  177.  
  178. cdef list GetTruePalette(unsigned char MinR, unsigned char MinG, unsigned char MinB, unsigned char MaxR, unsigned char MaxG, unsigned char MaxB, AlphaBlock):
  179.     cdef list Palette = [0] * 4
  180.  
  181.     if AlphaBlock:
  182.         Palette[0] = 0xFF000000 | int(MinR << 16) | int(MinG << 8) | MinB
  183.         Palette[1] = 0xFF000000 | int(MaxR << 16) | int(MaxG << 8) | MaxB
  184.         Palette[2] = 0xFF000000 | int((MaxR // 2 + MinR // 2) << 16) | int((MaxG // 2 + MinG // 2) << 8) | int(MaxB // 2 + MinB // 2)
  185.         Palette[3] = 0
  186.  
  187.     else:
  188.         Palette[0] = 0xFF000000 | int(MaxR << 16) | int(MaxG << 8) | MaxB
  189.         Palette[1] = 0xFF000000 | int(MinR << 16) | int(MinG << 8) | MinB
  190.         Palette[2] = 0xFF000000 | int((2 * MinR // 3 + 1 * MaxR // 3) << 16) | int((2 * MinG // 3 + 1 * MaxG // 3) << 8) | int(2 * MinB / 3 + 1 * MaxB / 3)
  191.         Palette[3] = 0xFF000000 | int((1 * MinR // 3 + 2 * MaxR // 3) << 16) | int((1 * MinG // 3 + 2 * MaxG // 3) << 8) | int(1 * MinB / 3 + 2 * MaxB / 3)
  192.  
  193.     return Palette
  194.  
  195. cdef unsigned short ToRGB565(unsigned char R, unsigned char G, unsigned char B):
  196.     return ((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3)
  197.  
  198.  
  199. cdef tuple FindColors(list Colors):
  200.     cdef unsigned char ThresholdMin = 0x02
  201.     cdef unsigned char ThresholdMax = 0xFD
  202.  
  203.     cdef unsigned char PartMin = 255
  204.     cdef unsigned char PartMax = 0
  205.     cdef unsigned char Min = 255
  206.     cdef unsigned char Max = 0
  207.     UseLessThanAlgorithm = False  # Used when colors are close to both 0 and 0xFF
  208.  
  209.     for Color in Colors:
  210.         if Color <= ThresholdMin:
  211.             UseLessThanAlgorithm = True
  212.  
  213.         elif Color >= ThresholdMax:
  214.             UseLessThanAlgorithm = True
  215.  
  216.         if not UseLessThanAlgorithm and Color < PartMin:
  217.             PartMin = Color
  218.  
  219.         if not UseLessThanAlgorithm and Color > PartMax:
  220.             PartMax = Color
  221.  
  222.         if Color < Min:
  223.             Min = Color
  224.  
  225.         if Color > Max:
  226.             Max = Color
  227.  
  228.     if Max <= 0x15 or (Min <= 0x05 and Max <= 0x30) or Min >= 0xEA or (Max >= 0xFA and Min >= 0xCF):  # What is good here?
  229.         UseLessThanAlgorithm = False
  230.  
  231.     else:
  232.         Max = PartMax
  233.         Min = PartMin
  234.  
  235.     if not UseLessThanAlgorithm and Min == Max:
  236.         Max -= 1
  237.  
  238.     Color0 = Min if UseLessThanAlgorithm else Max
  239.     Color1 = Max if UseLessThanAlgorithm else Min
  240.  
  241.     return Color0, Color1
  242.  
  243.  
  244. cpdef bytearray CompressBC3(SrcPtr, int Stride, int Width, int Height):
  245.     Stride //= 4
  246.  
  247.     print("Stride: %d" % Stride)
  248.     print("Width: %d" % Width)
  249.     print("Height: %d" % Height)
  250.     print("Uncompressed data length: %d" % len(SrcPtr))
  251.  
  252.     cdef bytearray DstPtr = bytearray()
  253.  
  254.     cdef int y, x, y2, x2, i
  255.  
  256.     # Messes up the alpha channel
  257.     # cdef int TransparentIndex
  258.  
  259.     cdef list Colors, Alphas, ActualColors, Palette, IndexBlock, AlphaIndexBlock
  260.     cdef bytearray ActualAlphas, AlphaPalette
  261.     cdef unsigned int pos, Color, Indices
  262.     cdef unsigned char A, R, G, B, MinR, MinG, MinB, MaxR, MaxG, MaxB, Alpha0, Alpha1
  263.     cdef unsigned short Color0, Color1
  264.     cdef unsigned long long AlphaIndices
  265.  
  266.     for y in range(0, Height, 4):
  267.         for x in range(0, Width, 4):
  268.             Colors = []
  269.             Alphas = []
  270.             ActualColors = [0] * 16
  271.             ActualAlphas =  bytearray(16)
  272.  
  273.             for y2 in range(4):
  274.                 for x2 in range(4):
  275.                     if y + y2 < Height and x + x2 < Width:
  276.                         # Read RGBA data and convert it to ARGB
  277.                         pos = (y + y2) * Stride + (x + x2)
  278.                         pos *= 4
  279.  
  280.                         A = SrcPtr[pos + 3]
  281.                         R = SrcPtr[pos]
  282.                         G = SrcPtr[pos + 1]
  283.                         B = SrcPtr[pos + 2]
  284.  
  285.                         Color = (A << 24) | (R << 16) | (G << 8) | B
  286.  
  287.                         Colors.append(Color)
  288.                         Alphas.append(A)
  289.                         ActualColors[y2 * 4 + x2] = Color
  290.                         ActualAlphas[y2 * 4 + x2] = A
  291.  
  292.             MinR, MinG, MinB, MaxR, MaxG, MaxB, TransparentBlock = FindMinMax(Colors)
  293.             Alpha0, Alpha1 = FindColors(Alphas)
  294.  
  295.             Color0 = ToRGB565(MaxR, MaxG, MaxB)
  296.             Color1 = ToRGB565(MinR, MinG, MinB)
  297.  
  298.             if Color0 == Color1:
  299.                 Color0 += 1
  300.  
  301.             #Palette = GetTruePalette(MinR, MinG, MinB, MaxR, MaxG, MaxB, False)
  302.             Palette = GetPalette(Color0, Color1)
  303.  
  304.             AlphaPalette = GetAlphaPalette(Alpha0, Alpha1)
  305.  
  306.             Indices = 0
  307.             AlphaIndices = 0
  308.  
  309.             if not TransparentBlock:
  310.                 IndexBlock = CompressBlock(ActualColors, Palette, Width, Height, x, y, 256 - (MaxR - MinR), 256 - (MaxG - MinG), 256 - (MaxB - MinB))
  311.                 AlphaIndexBlock = CompressAlphaBlock(ActualAlphas, AlphaPalette, Width, Height, x, y)
  312.  
  313.                 for y2 in range(4):
  314.                     for x2 in range(4):
  315.                         i = y2 * 4 + x2
  316.                         Indices |= IndexBlock[i] << (i * 2)
  317.                         AlphaIndices |= AlphaIndexBlock[i] << (i * 3)
  318.  
  319.             else:
  320.                 Indices = 0xFFFFFFFF
  321.  
  322.                 TransparentIndex = 0
  323.                 for i in range(len(AlphaPalette)):
  324.                     if not AlphaPalette[i]:
  325.                         TransparentIndex = i
  326.                         break
  327.  
  328.                 if AlphaPalette[TransparentIndex]:
  329.                     raise RuntimeError
  330.  
  331.                 for y2 in range(4):
  332.                     for x2 in range(4):
  333.                         AlphaIndices |= TransparentIndex << ((y2 * 4 + x2) * 3)
  334.  
  335.             DstPtr += bytes([Alpha0])
  336.             DstPtr += bytes([Alpha1])
  337.  
  338.             DstPtr += bytes([AlphaIndices & 0xFF])
  339.             DstPtr += bytes([(AlphaIndices >> 8) & 0xFF])
  340.             DstPtr += bytes([(AlphaIndices >> 16) & 0xFF])
  341.             DstPtr += bytes([(AlphaIndices >> 24) & 0xFF])
  342.             DstPtr += bytes([(AlphaIndices >> 32) & 0xFF])
  343.             DstPtr += bytes([(AlphaIndices >> 40) & 0xFF])
  344.  
  345.             DstPtr += bytes([Color0 & 0xFF])
  346.             DstPtr += bytes([(Color0 >> 8) & 0xFF])
  347.             DstPtr += bytes([Color1 & 0xFF])
  348.             DstPtr += bytes([(Color1 >> 8) & 0xFF])
  349.  
  350.             DstPtr += bytes([Indices & 0xFF])
  351.             DstPtr += bytes([(Indices >> 8) & 0xFF])
  352.             DstPtr += bytes([(Indices >> 16) & 0xFF])
  353.             DstPtr += bytes([(Indices >> 24) & 0xFF])
  354.  
  355.     return DstPtr
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement