• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2020-2022 Hans-Kristian Arntzen
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22  const ivec2 etc1_color_modifier_table[8] = ivec2[](
23     ivec2(2, 8),
24     ivec2(5, 17),
25     ivec2(9, 29),
26     ivec2(13, 42),
27     ivec2(18, 60),
28     ivec2(24, 80),
29     ivec2(33, 106),
30     ivec2(47, 183));
31 
32 const ivec4 etc2_alpha_modifier_table[16] = ivec4[](
33     ivec4(2, 5, 8, 14),
34     ivec4(2, 6, 9, 12),
35     ivec4(1, 4, 7, 12),
36     ivec4(1, 3, 5, 12),
37     ivec4(2, 5, 7, 11),
38     ivec4(2, 6, 8, 10),
39     ivec4(3, 6, 7, 10),
40     ivec4(2, 4, 7, 10),
41     ivec4(1, 5, 7, 9),
42     ivec4(1, 4, 7, 9),
43     ivec4(1, 3, 7, 9),
44     ivec4(1, 4, 6, 9),
45     ivec4(2, 3, 6, 9),
46     ivec4(0, 1, 2, 9),
47     ivec4(3, 5, 7, 8),
48     ivec4(2, 4, 6, 8)
49 );
50 
51 const int etc2_distance_table[8] = int[](3, 6, 11, 16, 23, 32, 41, 64);
52 
decode_etc2_alpha(uvec2 payload,int linear_pixel)53 int decode_etc2_alpha(uvec2 payload, int linear_pixel)
54 {
55     int bit_offset = 45 - 3 * linear_pixel;
56 #if R11
57     int base = isSigned !=0 ? bitfieldExtract(int(payload.y), 24, 8) : int(bitfieldExtract(payload.y, 24, 8));
58 #else
59     int base = int(bitfieldExtract(payload.y, 24, 8));
60 #endif
61     int multiplier = int(bitfieldExtract(payload.y, 20, 4));
62     int table = int(bitfieldExtract(payload.y, 16, 4));
63 
64     int lsb_index = int(bitfieldExtract(payload[bit_offset >> 5], bit_offset & 31, 2));
65     bit_offset += 2;
66     int msb = int((payload[bit_offset >> 5] >> (bit_offset & 31)) & 1u);
67     int mod = etc2_alpha_modifier_table[table][lsb_index] ^ (msb - 1);
68 #if R11
69     int a = base * 8 + 4;
70     a += multiplier != 0 ? mod * multiplier * 8 : mod;
71     int minValue = isSigned !=0 ? -1023: 0;
72     int maxValue = isSigned !=0 ? 1023 : 2047;
73     a = clamp(a, minValue, maxValue);
74     float scale = isSigned !=0 ? 127.0f : 255.0f;
75     return int(a/float(maxValue) * scale + 0.5f);
76 #else
77     int a = base + mod * multiplier;
78     return clamp(a, 0, 0xff);
79 #endif
80 }
81 
DecodeRGB(ivec2 pixel_coord,uvec2 color_payload,int linear_pixel,inout bool punchthrough)82  ivec4 DecodeRGB(ivec2 pixel_coord, uvec2 color_payload, int linear_pixel, inout bool punchthrough) {
83     int alpha_result = 0xff;
84     ivec3 rgb_result;
85     ivec3 base_rgb;
86     uint flip = color_payload.y & 1u;
87     uint subblock = uint((pixel_coord[flip] & 2) >> 1);
88     bool etc1_compat = false;
89 
90     if (alphaBits != 1 && (color_payload.y & 2u) == 0u)
91     {
92         // Individual mode (ETC1)
93         etc1_compat = true;
94         base_rgb = ivec3(color_payload.yyy >> (uvec3(28, 20, 12) - 4u * subblock));
95         base_rgb &= 0xf;
96         base_rgb *= 0x11;
97     }
98     else
99     {
100         int r = int(bitfieldExtract(color_payload.y, 27, 5));
101         int rd = bitfieldExtract(int(color_payload.y), 24, 3);
102         int g = int(bitfieldExtract(color_payload.y, 19, 5));
103         int gd = bitfieldExtract(int(color_payload.y), 16, 3);
104         int b = int(bitfieldExtract(color_payload.y, 11, 5));
105         int bd = bitfieldExtract(int(color_payload.y), 8, 3);
106 
107         int r1 = r + rd;
108         int g1 = g + gd;
109         int b1 = b + bd;
110 
111         if (uint(r1) > 31u) // T mode
112         {
113             int r1 = int(bitfieldExtract(color_payload.y, 56 - 32, 2)) |
114                     (int(bitfieldExtract(color_payload.y, 59 - 32, 2)) << 2);
115             int g1 = int(bitfieldExtract(color_payload.y, 52 - 32, 4));
116             int b1 = int(bitfieldExtract(color_payload.y, 48 - 32, 4));
117             int r2 = int(bitfieldExtract(color_payload.y, 44 - 32, 4));
118             int g2 = int(bitfieldExtract(color_payload.y, 40 - 32, 4));
119             int b2 = int(bitfieldExtract(color_payload.y, 36 - 32, 4));
120             uint da = (bitfieldExtract(color_payload.y, 34 - 32, 2) << 1) |
121                     (color_payload.y & 1u);
122             int dist = etc2_distance_table[da];
123 
124             int msb = int((color_payload.x >> (15 + linear_pixel)) & 2u);
125             int lsb = int((color_payload.x >> linear_pixel) & 1u);
126             int index = msb | lsb;
127 
128             if (punchthrough)
129                 punchthrough = index == 2;
130 
131             if (index == 0)
132             {
133                 rgb_result = ivec3(r1, g1, b1);
134                 rgb_result *= 0x11;
135             }
136             else
137             {
138                 int mod = 2 - index;
139                 ivec3 rgb = ivec3(r2, g2, b2) * 0x11 + mod * dist;
140                 rgb_result = ivec3(clamp(rgb, ivec3(0), ivec3(255)));
141             }
142         }
143         else if (uint(g1) > 31u) // H mode
144         {
145             int r1 = int(bitfieldExtract(color_payload.y, 59 - 32, 4));
146             int g1 = (int(bitfieldExtract(color_payload.y, 56 - 32, 3)) << 1) |
147                     int((color_payload.y >> 20u) & 1u);
148             int b1 = int(bitfieldExtract(color_payload.y, 47 - 32, 3)) |
149                     int((color_payload.y >> 16u) & 8u);
150             int r2 = int(bitfieldExtract(color_payload.y, 43 - 32, 4));
151             int g2 = int(bitfieldExtract(color_payload.y, 39 - 32, 4));
152             int b2 = int(bitfieldExtract(color_payload.y, 35 - 32, 4));
153             uint da = color_payload.y & 4u;
154             uint db = color_payload.y & 1u;
155             uint d = da + 2u * db;
156             d += uint((r1 * 0x10000 + g1 * 0x100 + b1) >= (r2 * 0x10000 + g2 * 0x100 + b2));
157             int dist = etc2_distance_table[d];
158             int msb = int((color_payload.x >> (15 + linear_pixel)) & 2u);
159             int lsb = int((color_payload.x >> linear_pixel) & 1u);
160 
161             if (punchthrough)
162                 punchthrough = (msb + lsb) == 2;
163 
164             ivec3 base = msb != 0 ? ivec3(r2, g2, b2) : ivec3(r1, g1, b1);
165             base *= 0x11;
166             int mod = 1 - 2 * lsb;
167             base += mod * dist;
168             rgb_result = ivec3(clamp(base, ivec3(0), ivec3(0xff)));
169         }
170         else if (uint(b1) > 31u) // plane mode
171         {
172             // Planar mode
173             int r = int(bitfieldExtract(color_payload.y, 57 - 32, 6));
174             int g = int(bitfieldExtract(color_payload.y, 49 - 32, 6)) |
175                     (int(color_payload.y >> 18) & 0x40);
176             int b = int(bitfieldExtract(color_payload.y, 39 - 32, 3)) |
177                     (int(bitfieldExtract(color_payload.y, 43 - 32, 2)) << 3) |
178                     (int(color_payload.y >> 11) & 0x20);
179             int rh = int(color_payload.y & 1u) |
180                     (int(bitfieldExtract(color_payload.y, 2, 5)) << 1);
181             int rv = int(bitfieldExtract(color_payload.x, 13, 6));
182             int gh = int(bitfieldExtract(color_payload.x, 25, 7));
183             int gv = int(bitfieldExtract(color_payload.x, 6, 7));
184             int bh = int(bitfieldExtract(color_payload.x, 19, 6));
185             int bv = int(bitfieldExtract(color_payload.x, 0, 6));
186 
187             r = (r << 2) | (r >> 4);
188             rh = (rh << 2) | (rh >> 4);
189             rv = (rv << 2) | (rv >> 4);
190             g = (g << 1) | (g >> 6);
191             gh = (gh << 1) | (gh >> 6);
192             gv = (gv << 1) | (gv >> 6);
193             b = (b << 2) | (b >> 4);
194             bh = (bh << 2) | (bh >> 4);
195             bv = (bv << 2) | (bv >> 4);
196 
197             ivec3 rgb = ivec3(r, g, b);
198             ivec3 dx = ivec3(rh, gh, bh) - rgb;
199             ivec3 dy = ivec3(rv, gv, bv) - rgb;
200             dx *= int(pixel_coord.x);
201             dy *= int(pixel_coord.y);
202             rgb = rgb + ((dx + dy + 2) >> 2);
203             rgb = clamp(rgb, ivec3(0), ivec3(255));
204             rgb_result = ivec3(rgb);
205 
206             punchthrough = false;
207 
208         }
209         else // diff mode
210         {
211             // Differential mode (ETC1)
212             etc1_compat = true;
213             base_rgb = ivec3(r, g, b) + int(subblock) * ivec3(rd, gd, bd);
214             base_rgb = (base_rgb << 3) | (base_rgb >> 2);
215         }
216     }
217 
218     if (etc1_compat)
219     {
220         uint etc1_table_index = bitfieldExtract(color_payload.y, 5 - 3 * int(subblock != 0u), 3);
221         int msb = int((color_payload.x >> (15 + linear_pixel)) & 2u);
222         int lsb = int((color_payload.x >> linear_pixel) & 1u);
223         int sgn = 1 - msb;
224 
225         if (punchthrough)
226         {
227             sgn *= lsb;
228             punchthrough = (msb + lsb) == 2;
229         }
230 
231         int offset = etc1_color_modifier_table[etc1_table_index][lsb] * sgn;
232         base_rgb = clamp(base_rgb + offset, ivec3(0), ivec3(255));
233         rgb_result = ivec3(base_rgb);
234     }
235 
236     if (alphaBits == 1 && punchthrough)
237     {
238         rgb_result = ivec3(0);
239         alpha_result = 0;
240     }
241 
242     return ivec4(rgb_result.r, rgb_result.g, rgb_result.b, alpha_result);
243 }