Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 int clampByte(int value) |
| 20 | { |
| 21 | return (value < 0) ? 0 : ((value > 255) ? 255 : value); |
| 22 | } |
| 23 | |
| 24 | inline int clampSByte(int value) |
| 25 | { |
| 26 | return (value < -128) ? -128 : ((value > 127) ? 127 : value); |
| 27 | } |
| 28 | |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 29 | inline int clampEAC(int value, bool isSigned) |
| 30 | { |
| 31 | int min = isSigned ? -1023 : 0; |
| 32 | int max = isSigned ? 1023 : 2047; |
| 33 | return (value < min) ? min : ((value > max) ? max : value); |
| 34 | } |
| 35 | |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 = static_cast<unsigned char>(clampByte(red)); |
| 50 | g = static_cast<unsigned char>(clampByte(green)); |
| 51 | b = static_cast<unsigned char>(clampByte(blue)); |
| 52 | } |
| 53 | |
| 54 | inline void set(int red, int green, int blue, int alpha) |
| 55 | { |
| 56 | r = static_cast<unsigned char>(clampByte(red)); |
| 57 | g = static_cast<unsigned char>(clampByte(green)); |
| 58 | b = static_cast<unsigned char>(clampByte(blue)); |
| 59 | a = static_cast<unsigned char>(clampByte(alpha)); |
| 60 | } |
| 61 | |
| 62 | const bgra8& addA(int 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 |
Alexis Hetu | f08be92 | 2017-12-18 17:17:55 -0500 | [diff] [blame] | 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) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 93 | { |
Alexis Hetu | f08be92 | 2017-12-18 17:17:55 -0500 | [diff] [blame] | 94 | if(isEAC) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 95 | { |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 96 | for(int j = 0; j < 4 && (y + j) < h; j++) |
| 97 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 98 | int* sDst = reinterpret_cast<int*>(dest); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 99 | for(int i = 0; i < 4 && (x + i) < w; i++) |
| 100 | { |
| 101 | for(int c = nbChannels - 1; c >= 0; c--) |
| 102 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 103 | sDst[i * nbChannels + c] = clampEAC(sources[c]->getSingleChannel(i, j, isSigned, true), isSigned); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 104 | } |
| 105 | } |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 106 | dest += pitch; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 107 | } |
| 108 | } |
| 109 | else |
| 110 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 111 | if(isSigned) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 112 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 113 | signed char* sDst = reinterpret_cast<signed char*>(dest); |
| 114 | for(int j = 0; j < 4 && (y + j) < h; j++) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 115 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 116 | for(int i = 0; i < 4 && (x + i) < w; i++) |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 117 | { |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 118 | for(int c = nbChannels - 1; c >= 0; c--) |
| 119 | { |
| 120 | sDst[i * nbChannels + c] = clampSByte(sources[c]->getSingleChannel(i, j, isSigned, false)); |
| 121 | } |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 122 | } |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 123 | sDst += pitch; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 124 | } |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 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 | } |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 619 | inline int getSingleChannel(int x, int y, bool isSigned, bool isEAC) const |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 620 | { |
| 621 | int codeword = isSigned ? signed_base_codeword : base_codeword; |
Alexis Hetu | f46493f | 2017-12-18 15:32:26 -0500 | [diff] [blame] | 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; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 | { |
Alexis Hetu | f08be92 | 2017-12-18 17:17:55 -0500 | [diff] [blame] | 693 | ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 1, x, y, dstW, dstH, dstPitch, inputType == ETC_R_SIGNED, true); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 | { |
Alexis Hetu | f08be92 | 2017-12-18 17:17:55 -0500 | [diff] [blame] | 705 | ETC2::DecodeBlock(sources, dstRow + (x * dstBpp), 2, x, y, dstW, dstH, dstPitch, inputType == ETC_RG_SIGNED, true); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 |
Alexis Hetu | f08be92 | 2017-12-18 17:17:55 -0500 | [diff] [blame] | 727 | ETC2::DecodeBlock(&sources[0], &(alphaValues[0][0]), 1, x, y, dstW, dstH, 4, false, false); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 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 | } |