1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #include "ETC_Decoder.hpp" |
16 | |
17 | namespace |
18 | { |
19 | inline unsigned char clampByte(int value) |
20 | { |
21 | return static_cast<unsigned char>((value < 0) ? 0 : ((value > 255) ? 255 : value)); |
22 | } |
23 | |
24 | inline signed char clampSByte(int value) |
25 | { |
26 | return static_cast<signed char>((value < -128) ? -128 : ((value > 127) ? 127 : value)); |
27 | } |
28 | |
29 | inline short clampEAC(int value, bool isSigned) |
30 | { |
31 | short min = isSigned ? -1023 : 0; |
32 | short max = isSigned ? 1023 : 2047; |
33 | return static_cast<short>(((value < min) ? min : ((value > max) ? max : value)) << 5); |
34 | } |
35 | |
36 | struct bgra8 |
37 | { |
38 | unsigned char b; |
39 | unsigned char g; |
40 | unsigned char r; |
41 | unsigned char a; |
42 | |
43 | inline bgra8() |
44 | { |
45 | } |
46 | |
47 | inline void set(int red, int green, int blue) |
48 | { |
49 | r = clampByte(red); |
50 | g = clampByte(green); |
51 | b = clampByte(blue); |
52 | } |
53 | |
54 | inline void set(int red, int green, int blue, int alpha) |
55 | { |
56 | r = clampByte(red); |
57 | g = clampByte(green); |
58 | b = clampByte(blue); |
59 | a = clampByte(alpha); |
60 | } |
61 | |
62 | const bgra8& addA(unsigned char alpha) |
63 | { |
64 | a = alpha; |
65 | return *this; |
66 | } |
67 | }; |
68 | |
69 | inline int extend_4to8bits(int x) |
70 | { |
71 | return (x << 4) | x; |
72 | } |
73 | |
74 | inline int extend_5to8bits(int x) |
75 | { |
76 | return (x << 3) | (x >> 2); |
77 | } |
78 | |
79 | inline int extend_6to8bits(int x) |
80 | { |
81 | return (x << 2) | (x >> 4); |
82 | } |
83 | |
84 | inline int extend_7to8bits(int x) |
85 | { |
86 | return (x << 1) | (x >> 6); |
87 | } |
88 | |
89 | struct ETC2 |
90 | { |
91 | // Decodes unsigned single or dual channel block to bytes |
92 | static void DecodeBlock(const ETC2** sources, unsigned char *dest, int nbChannels, int x, int y, int w, int h, int pitch, bool isSigned, bool isEAC) |
93 | { |
94 | if(isEAC) |
95 | { |
96 | for(int j = 0; j < 4 && (y + j) < h; j++) |
97 | { |
98 | short* sDst = reinterpret_cast<short*>(dest); |
99 | for(int i = 0; i < 4 && (x + i) < w; i++) |
100 | { |
101 | for(int c = nbChannels - 1; c >= 0; c--) |
102 | { |
103 | sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned); |
104 | } |
105 | } |
106 | dest += pitch; |
107 | } |
108 | } |
109 | else |
110 | { |
111 | if(isSigned) |
112 | { |
113 | signed char* sDst = reinterpret_cast<signed char*>(dest); |
114 | for(int j = 0; j < 4 && (y + j) < h; j++) |
115 | { |
116 | for(int i = 0; i < 4 && (x + i) < w; i++) |
117 | { |
118 | for(int c = nbChannels - 1; c >= 0; c--) |
119 | { |
120 | sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned, false)); |
121 | } |
122 | } |
123 | sDst += pitch; |
124 | } |
125 | } |
126 | else |
127 | { |
128 | for(int j = 0; j < 4 && (y + j) < h; j++) |
129 | { |
130 | for(int i = 0; i < 4 && (x + i) < w; i++) |
131 | { |
132 | for(int c = nbChannels - 1; c >= 0; c--) |
133 | { |
134 | dest[i * nbChannels + c] = clampByte(sources[c]->getSingleChannel(i, j, isSigned, false)); |
135 | } |
136 | } |
137 | dest += pitch; |
138 | } |
139 | } |
140 | } |
141 | } |
142 | |
143 | // Decodes RGB block to bgra8 |
144 | void decodeBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool punchThroughAlpha) const |
145 | { |
146 | bool opaqueBit = diffbit; |
147 | bool nonOpaquePunchThroughAlpha = punchThroughAlpha && !opaqueBit; |
148 | |
149 | // Select mode |
150 | if(diffbit || punchThroughAlpha) |
151 | { |
152 | int r = (R + dR); |
153 | int g = (G + dG); |
154 | int b = (B + dB); |
155 | if(r < 0 || r > 31) |
156 | { |
157 | decodeTBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha); |
158 | } |
159 | else if(g < 0 || g > 31) |
160 | { |
161 | decodeHBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha); |
162 | } |
163 | else if(b < 0 || b > 31) |
164 | { |
165 | decodePlanarBlock(dest, x, y, w, h, pitch, alphaValues); |
166 | } |
167 | else |
168 | { |
169 | decodeDifferentialBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha); |
170 | } |
171 | } |
172 | else |
173 | { |
174 | decodeIndividualBlock(dest, x, y, w, h, pitch, alphaValues, nonOpaquePunchThroughAlpha); |
175 | } |
176 | } |
177 | |
178 | private: |
179 | struct |
180 | { |
181 | union |
182 | { |
183 | // Individual, differential, H and T modes |
184 | struct |
185 | { |
186 | union |
187 | { |
188 | // Individual and differential modes |
189 | struct |
190 | { |
191 | union |
192 | { |
193 | struct // Individual colors |
194 | { |
195 | unsigned char R2 : 4; |
196 | unsigned char R1 : 4; |
197 | unsigned char G2 : 4; |
198 | unsigned char G1 : 4; |
199 | unsigned char B2 : 4; |
200 | unsigned char B1 : 4; |
201 | }; |
202 | |
203 | struct // Differential colors |
204 | { |
205 | signed char dR : 3; |
206 | unsigned char R : 5; |
207 | signed char dG : 3; |
208 | unsigned char G : 5; |
209 | signed char dB : 3; |
210 | unsigned char B : 5; |
211 | }; |
212 | }; |
213 | |
214 | bool flipbit : 1; |
215 | bool diffbit : 1; |
216 | unsigned char cw2 : 3; |
217 | unsigned char cw1 : 3; |
218 | }; |
219 | |
220 | // T mode |
221 | struct |
222 | { |
223 | // Byte 1 |
224 | unsigned char TR1b : 2; |
225 | unsigned char TdummyB : 1; |
226 | unsigned char TR1a : 2; |
227 | unsigned char TdummyA : 3; |
228 | |
229 | // Byte 2 |
230 | unsigned char TB1 : 4; |
231 | unsigned char TG1 : 4; |
232 | |
233 | // Byte 3 |
234 | unsigned char TG2 : 4; |
235 | unsigned char TR2 : 4; |
236 | |
237 | // Byte 4 |
238 | unsigned char Tdb : 1; |
239 | bool Tflipbit : 1; |
240 | unsigned char Tda : 2; |
241 | unsigned char TB2 : 4; |
242 | }; |
243 | |
244 | // H mode |
245 | struct |
246 | { |
247 | // Byte 1 |
248 | unsigned char HG1a : 3; |
249 | unsigned char HR1 : 4; |
250 | unsigned char HdummyA : 1; |
251 | |
252 | // Byte 2 |
253 | unsigned char HB1b : 2; |
254 | unsigned char HdummyC : 1; |
255 | unsigned char HB1a : 1; |
256 | unsigned char HG1b : 1; |
257 | unsigned char HdummyB : 3; |
258 | |
259 | // Byte 3 |
260 | unsigned char HG2a : 3; |
261 | unsigned char HR2 : 4; |
262 | unsigned char HB1c : 1; |
263 | |
264 | // Byte 4 |
265 | unsigned char Hdb : 1; |
266 | bool Hflipbit : 1; |
267 | unsigned char Hda : 1; |
268 | unsigned char HB2 : 4; |
269 | unsigned char HG2b : 1; |
270 | }; |
271 | }; |
272 | |
273 | unsigned char pixelIndexMSB[2]; |
274 | unsigned char pixelIndexLSB[2]; |
275 | }; |
276 | |
277 | // planar mode |
278 | struct |
279 | { |
280 | // Byte 1 |
281 | unsigned char GO1 : 1; |
282 | unsigned char RO : 6; |
283 | unsigned char PdummyA : 1; |
284 | |
285 | // Byte 2 |
286 | unsigned char BO1 : 1; |
287 | unsigned char GO2 : 6; |
288 | unsigned char PdummyB : 1; |
289 | |
290 | // Byte 3 |
291 | unsigned char BO3a : 2; |
292 | unsigned char PdummyD : 1; |
293 | unsigned char BO2 : 2; |
294 | unsigned char PdummyC : 3; |
295 | |
296 | // Byte 4 |
297 | unsigned char RH2 : 1; |
298 | bool Pflipbit : 1; |
299 | unsigned char RH1 : 5; |
300 | unsigned char BO3b : 1; |
301 | |
302 | // Byte 5 |
303 | unsigned char BHa : 1; |
304 | unsigned char GH : 7; |
305 | |
306 | // Byte 6 |
307 | unsigned char RVa : 3; |
308 | unsigned char BHb : 5; |
309 | |
310 | // Byte 7 |
311 | unsigned char GVa : 5; |
312 | unsigned char RVb : 3; |
313 | |
314 | // Byte 8 |
315 | unsigned char BV : 6; |
316 | unsigned char GVb : 2; |
317 | }; |
318 | |
319 | // Single channel block |
320 | struct |
321 | { |
322 | union |
323 | { |
324 | unsigned char base_codeword; |
325 | signed char signed_base_codeword; |
326 | }; |
327 | |
328 | unsigned char table_index : 4; |
329 | unsigned char multiplier : 4; |
330 | |
331 | unsigned char mc1 : 2; |
332 | unsigned char mb : 3; |
333 | unsigned char ma : 3; |
334 | |
335 | unsigned char mf1 : 1; |
336 | unsigned char me : 3; |
337 | unsigned char md : 3; |
338 | unsigned char mc2 : 1; |
339 | |
340 | unsigned char mh : 3; |
341 | unsigned char mg : 3; |
342 | unsigned char mf2 : 2; |
343 | |
344 | unsigned char mk1 : 2; |
345 | unsigned char mj : 3; |
346 | unsigned char mi : 3; |
347 | |
348 | unsigned char mn1 : 1; |
349 | unsigned char mm : 3; |
350 | unsigned char ml : 3; |
351 | unsigned char mk2 : 1; |
352 | |
353 | unsigned char mp : 3; |
354 | unsigned char mo : 3; |
355 | unsigned char mn2 : 2; |
356 | }; |
357 | }; |
358 | }; |
359 | |
360 | void decodeIndividualBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const |
361 | { |
362 | int r1 = extend_4to8bits(R1); |
363 | int g1 = extend_4to8bits(G1); |
364 | int b1 = extend_4to8bits(B1); |
365 | |
366 | int r2 = extend_4to8bits(R2); |
367 | int g2 = extend_4to8bits(G2); |
368 | int b2 = extend_4to8bits(B2); |
369 | |
370 | decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha); |
371 | } |
372 | |
373 | void decodeDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const |
374 | { |
375 | int b1 = extend_5to8bits(B); |
376 | int g1 = extend_5to8bits(G); |
377 | int r1 = extend_5to8bits(R); |
378 | |
379 | int r2 = extend_5to8bits(R + dR); |
380 | int g2 = extend_5to8bits(G + dG); |
381 | int b2 = extend_5to8bits(B + dB); |
382 | |
383 | decodeIndividualOrDifferentialBlock(dest, x, y, w, h, pitch, r1, g1, b1, r2, g2, b2, alphaValues, nonOpaquePunchThroughAlpha); |
384 | } |
385 | |
386 | void decodeIndividualOrDifferentialBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, int r1, int g1, int b1, int r2, int g2, int b2, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const |
387 | { |
388 | // Table 3.17.2 sorted according to table 3.17.3 |
389 | static const int intensityModifierDefault[8][4] = |
390 | { |
391 | { 2, 8, -2, -8 }, |
392 | { 5, 17, -5, -17 }, |
393 | { 9, 29, -9, -29 }, |
394 | { 13, 42, -13, -42 }, |
395 | { 18, 60, -18, -60 }, |
396 | { 24, 80, -24, -80 }, |
397 | { 33, 106, -33, -106 }, |
398 | { 47, 183, -47, -183 } |
399 | }; |
400 | |
401 | // Table C.12, intensity modifier for non opaque punchthrough alpha |
402 | static const int intensityModifierNonOpaque[8][4] = |
403 | { |
404 | { 0, 8, 0, -8 }, |
405 | { 0, 17, 0, -17 }, |
406 | { 0, 29, 0, -29 }, |
407 | { 0, 42, 0, -42 }, |
408 | { 0, 60, 0, -60 }, |
409 | { 0, 80, 0, -80 }, |
410 | { 0, 106, 0, -106 }, |
411 | { 0, 183, 0, -183 } |
412 | }; |
413 | |
414 | const int(&intensityModifier)[8][4] = nonOpaquePunchThroughAlpha ? intensityModifierNonOpaque : intensityModifierDefault; |
415 | |
416 | bgra8 subblockColors0[4]; |
417 | bgra8 subblockColors1[4]; |
418 | |
419 | const int i10 = intensityModifier[cw1][0]; |
420 | const int i11 = intensityModifier[cw1][1]; |
421 | const int i12 = intensityModifier[cw1][2]; |
422 | const int i13 = intensityModifier[cw1][3]; |
423 | |
424 | subblockColors0[0].set(r1 + i10, g1 + i10, b1 + i10); |
425 | subblockColors0[1].set(r1 + i11, g1 + i11, b1 + i11); |
426 | subblockColors0[2].set(r1 + i12, g1 + i12, b1 + i12); |
427 | subblockColors0[3].set(r1 + i13, g1 + i13, b1 + i13); |
428 | |
429 | const int i20 = intensityModifier[cw2][0]; |
430 | const int i21 = intensityModifier[cw2][1]; |
431 | const int i22 = intensityModifier[cw2][2]; |
432 | const int i23 = intensityModifier[cw2][3]; |
433 | |
434 | subblockColors1[0].set(r2 + i20, g2 + i20, b2 + i20); |
435 | subblockColors1[1].set(r2 + i21, g2 + i21, b2 + i21); |
436 | subblockColors1[2].set(r2 + i22, g2 + i22, b2 + i22); |
437 | subblockColors1[3].set(r2 + i23, g2 + i23, b2 + i23); |
438 | |
439 | unsigned char* destStart = dest; |
440 | |
441 | if(flipbit) |
442 | { |
443 | for(int j = 0; j < 2 && (y + j) < h; j++) |
444 | { |
445 | bgra8* color = (bgra8*)dest; |
446 | if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]); |
447 | if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]); |
448 | if((x + 2) < w) color[2] = subblockColors0[getIndex(2, j)].addA(alphaValues[j][2]); |
449 | if((x + 3) < w) color[3] = subblockColors0[getIndex(3, j)].addA(alphaValues[j][3]); |
450 | dest += pitch; |
451 | } |
452 | |
453 | for(int j = 2; j < 4 && (y + j) < h; j++) |
454 | { |
455 | bgra8* color = (bgra8*)dest; |
456 | if((x + 0) < w) color[0] = subblockColors1[getIndex(0, j)].addA(alphaValues[j][0]); |
457 | if((x + 1) < w) color[1] = subblockColors1[getIndex(1, j)].addA(alphaValues[j][1]); |
458 | if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]); |
459 | if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]); |
460 | dest += pitch; |
461 | } |
462 | } |
463 | else |
464 | { |
465 | for(int j = 0; j < 4 && (y + j) < h; j++) |
466 | { |
467 | bgra8* color = (bgra8*)dest; |
468 | if((x + 0) < w) color[0] = subblockColors0[getIndex(0, j)].addA(alphaValues[j][0]); |
469 | if((x + 1) < w) color[1] = subblockColors0[getIndex(1, j)].addA(alphaValues[j][1]); |
470 | if((x + 2) < w) color[2] = subblockColors1[getIndex(2, j)].addA(alphaValues[j][2]); |
471 | if((x + 3) < w) color[3] = subblockColors1[getIndex(3, j)].addA(alphaValues[j][3]); |
472 | dest += pitch; |
473 | } |
474 | } |
475 | |
476 | if(nonOpaquePunchThroughAlpha) |
477 | { |
478 | decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch); |
479 | } |
480 | } |
481 | |
482 | void decodeTBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const |
483 | { |
484 | // Table C.8, distance index fot T and H modes |
485 | static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 }; |
486 | |
487 | bgra8 paintColors[4]; |
488 | |
489 | int r1 = extend_4to8bits(TR1a << 2 | TR1b); |
490 | int g1 = extend_4to8bits(TG1); |
491 | int b1 = extend_4to8bits(TB1); |
492 | |
493 | int r2 = extend_4to8bits(TR2); |
494 | int g2 = extend_4to8bits(TG2); |
495 | int b2 = extend_4to8bits(TB2); |
496 | |
497 | const int d = distance[Tda << 1 | Tdb]; |
498 | |
499 | paintColors[0].set(r1, g1, b1); |
500 | paintColors[1].set(r2 + d, g2 + d, b2 + d); |
501 | paintColors[2].set(r2, g2, b2); |
502 | paintColors[3].set(r2 - d, g2 - d, b2 - d); |
503 | |
504 | unsigned char* destStart = dest; |
505 | |
506 | for(int j = 0; j < 4 && (y + j) < h; j++) |
507 | { |
508 | bgra8* color = (bgra8*)dest; |
509 | if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]); |
510 | if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]); |
511 | if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]); |
512 | if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]); |
513 | dest += pitch; |
514 | } |
515 | |
516 | if(nonOpaquePunchThroughAlpha) |
517 | { |
518 | decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch); |
519 | } |
520 | } |
521 | |
522 | void decodeHBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4], bool nonOpaquePunchThroughAlpha) const |
523 | { |
524 | // Table C.8, distance index fot T and H modes |
525 | static const int distance[8] = { 3, 6, 11, 16, 23, 32, 41, 64 }; |
526 | |
527 | bgra8 paintColors[4]; |
528 | |
529 | int r1 = extend_4to8bits(HR1); |
530 | int g1 = extend_4to8bits(HG1a << 1 | HG1b); |
531 | int b1 = extend_4to8bits(HB1a << 3 | HB1b << 1 | HB1c); |
532 | |
533 | int r2 = extend_4to8bits(HR2); |
534 | int g2 = extend_4to8bits(HG2a << 1 | HG2b); |
535 | int b2 = extend_4to8bits(HB2); |
536 | |
537 | const int d = distance[(Hda << 2) | (Hdb << 1) | ((r1 << 16 | g1 << 8 | b1) >= (r2 << 16 | g2 << 8 | b2) ? 1 : 0)]; |
538 | |
539 | paintColors[0].set(r1 + d, g1 + d, b1 + d); |
540 | paintColors[1].set(r1 - d, g1 - d, b1 - d); |
541 | paintColors[2].set(r2 + d, g2 + d, b2 + d); |
542 | paintColors[3].set(r2 - d, g2 - d, b2 - d); |
543 | |
544 | unsigned char* destStart = dest; |
545 | |
546 | for(int j = 0; j < 4 && (y + j) < h; j++) |
547 | { |
548 | bgra8* color = (bgra8*)dest; |
549 | if((x + 0) < w) color[0] = paintColors[getIndex(0, j)].addA(alphaValues[j][0]); |
550 | if((x + 1) < w) color[1] = paintColors[getIndex(1, j)].addA(alphaValues[j][1]); |
551 | if((x + 2) < w) color[2] = paintColors[getIndex(2, j)].addA(alphaValues[j][2]); |
552 | if((x + 3) < w) color[3] = paintColors[getIndex(3, j)].addA(alphaValues[j][3]); |
553 | dest += pitch; |
554 | } |
555 | |
556 | if(nonOpaquePunchThroughAlpha) |
557 | { |
558 | decodePunchThroughAlphaBlock(destStart, x, y, w, h, pitch); |
559 | } |
560 | } |
561 | |
562 | void decodePlanarBlock(unsigned char *dest, int x, int y, int w, int h, int pitch, unsigned char alphaValues[4][4]) const |
563 | { |
564 | int ro = extend_6to8bits(RO); |
565 | int go = extend_7to8bits(GO1 << 6 | GO2); |
566 | int bo = extend_6to8bits(BO1 << 5 | BO2 << 3 | BO3a << 1 | BO3b); |
567 | |
568 | int rh = extend_6to8bits(RH1 << 1 | RH2); |
569 | int gh = extend_7to8bits(GH); |
570 | int bh = extend_6to8bits(BHa << 5 | BHb); |
571 | |
572 | int rv = extend_6to8bits(RVa << 3 | RVb); |
573 | int gv = extend_7to8bits(GVa << 2 | GVb); |
574 | int bv = extend_6to8bits(BV); |
575 | |
576 | for(int j = 0; j < 4 && (y + j) < h; j++) |
577 | { |
578 | int ry = j * (rv - ro) + 2; |
579 | int gy = j * (gv - go) + 2; |
580 | int by = j * (bv - bo) + 2; |
581 | for(int i = 0; i < 4 && (x + i) < w; i++) |
582 | { |
583 | ((bgra8*)(dest))[i].set(((i * (rh - ro) + ry) >> 2) + ro, |
584 | ((i * (gh - go) + gy) >> 2) + go, |
585 | ((i * (bh - bo) + by) >> 2) + bo, |
586 | alphaValues[j][i]); |
587 | } |
588 | dest += pitch; |
589 | } |
590 | } |
591 | |
592 | // Index for individual, differential, H and T modes |
593 | inline int getIndex(int x, int y) const |
594 | { |
595 | int bitIndex = x * 4 + y; |
596 | int bitOffset = bitIndex & 7; |
597 | int lsb = (pixelIndexLSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; |
598 | int msb = (pixelIndexMSB[1 - (bitIndex >> 3)] >> bitOffset) & 1; |
599 | |
600 | return (msb << 1) | lsb; |
601 | } |
602 | |
603 | void decodePunchThroughAlphaBlock(unsigned char *dest, int x, int y, int w, int h, int pitch) const |
604 | { |
605 | for(int j = 0; j < 4 && (y + j) < h; j++) |
606 | { |
607 | for(int i = 0; i < 4 && (x + i) < w; i++) |
608 | { |
609 | if(getIndex(i, j) == 2) // msb == 1 && lsb == 0 |
610 | { |
611 | ((bgra8*)dest)[i].set(0, 0, 0, 0); |
612 | } |
613 | } |
614 | dest += pitch; |
615 | } |
616 | } |
617 | |
618 | // Single channel utility functions |
619 | inline int getSingleChannel(int x, int y, bool isSigned, bool isEAC) const |
620 | { |
621 | int codeword = isSigned ? signed_base_codeword : base_codeword; |
622 | return isEAC ? |
623 | ((multiplier == 0) ? |
624 | (codeword * 8 + 4 + getSingleChannelModifier(x, y)) : |
625 | (codeword * 8 + 4 + getSingleChannelModifier(x, y) * multiplier * 8)) : |
626 | codeword + getSingleChannelModifier(x, y) * multiplier; |
627 | } |
628 | |
629 | inline int getSingleChannelIndex(int x, int y) const |
630 | { |
631 | switch(x * 4 + y) |
632 | { |
633 | case 0: return ma; |
634 | case 1: return mb; |
635 | case 2: return mc1 << 1 | mc2; |
636 | case 3: return md; |
637 | case 4: return me; |
638 | case 5: return mf1 << 2 | mf2; |
639 | case 6: return mg; |
640 | case 7: return mh; |
641 | case 8: return mi; |
642 | case 9: return mj; |
643 | case 10: return mk1 << 1 | mk2; |
644 | case 11: return ml; |
645 | case 12: return mm; |
646 | case 13: return mn1 << 2 | mn2; |
647 | case 14: return mo; |
648 | default: return mp; // 15 |
649 | } |
650 | } |
651 | |
652 | inline int getSingleChannelModifier(int x, int y) const |
653 | { |
654 | static const int modifierTable[16][8] = { { -3, -6, -9, -15, 2, 5, 8, 14 }, |
655 | { -3, -7, -10, -13, 2, 6, 9, 12 }, |
656 | { -2, -5, -8, -13, 1, 4, 7, 12 }, |
657 | { -2, -4, -6, -13, 1, 3, 5, 12 }, |
658 | { -3, -6, -8, -12, 2, 5, 7, 11 }, |
659 | { -3, -7, -9, -11, 2, 6, 8, 10 }, |
660 | { -4, -7, -8, -11, 3, 6, 7, 10 }, |
661 | { -3, -5, -8, -11, 2, 4, 7, 10 }, |
662 | { -2, -6, -8, -10, 1, 5, 7, 9 }, |
663 | { -2, -5, -8, -10, 1, 4, 7, 9 }, |
664 | { -2, -4, -8, -10, 1, 3, 7, 9 }, |
665 | { -2, -5, -7, -10, 1, 4, 6, 9 }, |
666 | { -3, -4, -7, -10, 2, 3, 6, 9 }, |
667 | { -1, -2, -3, -10, 0, 1, 2, 9 }, |
668 | { -4, -6, -8, -9, 3, 5, 7, 8 }, |
669 | { -3, -5, -7, -9, 2, 4, 6, 8 } }; |
670 | |
671 | return modifierTable[table_index][getSingleChannelIndex(x, y)]; |
672 | } |
673 | }; |
674 | } |
675 | |
676 | // Decodes 1 to 4 channel images to 8 bit output |
677 | bool ETC_Decoder::Decode(const unsigned char* src, unsigned char *dst, int w, int h, int dstW, int dstH, int dstPitch, int dstBpp, InputType inputType) |
678 | { |
679 | const ETC2* sources[2]; |
680 | sources[0] = (const ETC2*)src; |
681 | |
682 | unsigned char alphaValues[4][4] = { { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 }, { 255, 255, 255, 255 } }; |
683 | |
684 | switch(inputType) |
685 | { |
686 | case ETC_R_SIGNED: |
687 | case ETC_R_UNSIGNED: |
688 | for(int y = 0; y < h; y += 4) |
689 | { |
690 | unsigned char *dstRow = dst + (y * dstPitch); |
691 | for(int x = 0; x < w; x += 4, sources[0]++) |
692 | { |
693 | ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED, true); |
694 | } |
695 | } |
696 | break; |
697 | case ETC_RG_SIGNED: |
698 | case ETC_RG_UNSIGNED: |
699 | sources[1] = sources[0] + 1; |
700 | for(int y = 0; y < h; y += 4) |
701 | { |
702 | unsigned char *dstRow = dst + (y * dstPitch); |
703 | for(int x = 0; x < w; x += 4, sources[0] += 2, sources[1] += 2) |
704 | { |
705 | ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED, true); |
706 | } |
707 | } |
708 | break; |
709 | case ETC_RGB: |
710 | case ETC_RGB_PUNCHTHROUGH_ALPHA: |
711 | for(int y = 0; y < h; y += 4) |
712 | { |
713 | unsigned char *dstRow = dst + (y * dstPitch); |
714 | for(int x = 0; x < w; x += 4, sources[0]++) |
715 | { |
716 | sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, inputType == ETC_RGB_PUNCHTHROUGH_ALPHA); |
717 | } |
718 | } |
719 | break; |
720 | case ETC_RGBA: |
721 | for(int y = 0; y < h; y += 4) |
722 | { |
723 | unsigned char *dstRow = dst + (y * dstPitch); |
724 | for(int x = 0; x < w; x += 4) |
725 | { |
726 | // Decode Alpha |
727 | ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false, false); |
728 | sources[0]++; // RGBA packets are 128 bits, so move on to the next 64 bit packet to decode the RGB color |
729 | |
730 | // Decode RGB |
731 | sources[0]->decodeBlock(dstRow + (x * dstBpp), x, y, dstW, dstH, dstPitch, alphaValues, false); |
732 | sources[0]++; |
733 | } |
734 | } |
735 | break; |
736 | default: |
737 | return false; |
738 | } |
739 | |
740 | return true; |
741 | } |
742 | |