18cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Copyright 2009 Google Inc. 28cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// 38cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Licensed under the Apache License, Version 2.0 (the "License"); 48cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// you may not use this file except in compliance with the License. 58cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// You may obtain a copy of the License at 68cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// 78cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// http://www.apache.org/licenses/LICENSE-2.0 88cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// 98cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Unless required by applicable law or agreed to in writing, software 108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// distributed under the License is distributed on an "AS IS" BASIS, 118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// See the License for the specific language governing permissions and 138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// limitations under the License. 148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com////////////////////////////////////////////////////////////////////////////////////////// 168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// This is a fork of the AOSP project ETC1 codec. The original code can be found 188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// at the following web site: 198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// https://android.googlesource.com/platform/frameworks/native/+/master/opengl/include/ETC1/ 208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com////////////////////////////////////////////////////////////////////////////////////////// 228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com#include "etc1.h" 248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com#include <cstring> 268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt 288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com The number of bits that represent a 4x4 texel block is 64 bits if 308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com <internalformat> is given by ETC1_RGB8_OES. 318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com The data for a block is a number of bytes, 338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com {q0, q1, q2, q3, q4, q5, q6, q7} 358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com where byte q0 is located at the lowest memory address and q7 at 378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com the highest. The 64 bits specifying the block is then represented 388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com by the following 64 bit integer: 398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; 418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ETC1_RGB8_OES: 438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com a) bit layout in bits 63 through 32 if diffbit = 0 458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | base col1 | base col2 | base col1 | base col2 | 498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| 508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com --------------------------------------------------- 548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | base col1 | base col2 | table | table |diff|flip| 558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | 568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com --------------------------------------------------- 578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b) bit layout in bits 63 through 32 if diffbit = 1 608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | base col1 | dcol 2 | base col1 | dcol 2 | 648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | 658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com --------------------------------------------------- 698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | base col 1 | dcol 2 | table | table |diff|flip| 708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | 718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com --------------------------------------------------- 728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com c) bit layout in bits 31 through 0 (in both cases) 758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | most significant pixel index bits | 798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| 808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----------------------------------------------- 818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com -------------------------------------------------- 848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | least significant pixel index bits | 858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | 868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com -------------------------------------------------- 878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: 908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com table codeword modifier table 928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ------------------ ---------------------- 938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 0 -8 -2 2 8 948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1 -17 -5 5 17 958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2 -29 -9 9 29 968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3 -42 -13 13 42 978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4 -60 -18 18 60 988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5 -80 -24 24 80 998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6 -106 -33 33 106 1008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 7 -183 -47 47 183 1018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com Add table 3.17.3 Mapping from pixel index values to modifier values for 1048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ETC1 compressed textures: 1058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pixel index value 1078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com --------------- 1088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com msb lsb resulting modifier value 1098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com ----- ----- ------------------------- 1108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1 1 -b (large negative value) 1118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1 0 -a (small negative value) 1128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 0 0 a (small positive value) 1138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 0 1 b (large positive value) 1148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com */ 1178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const int kModifierTable[] = { 1198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 0 */2, 8, -2, -8, 1208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 1 */5, 17, -5, -17, 1218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 2 */9, 29, -9, -29, 1228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 3 */13, 42, -13, -42, 1238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 4 */18, 60, -18, -60, 1248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 5 */24, 80, -24, -80, 1258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 6 */33, 106, -33, -106, 1268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com/* 7 */47, 183, -47, -183 }; 1278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; 1298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic inline etc1_byte clamp(int x) { 1318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); 1328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convert4To8(int b) { 1368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int c = b & 0xf; 1378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (c << 4) | c; 1388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convert5To8(int b) { 1428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int c = b & 0x1f; 1438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (c << 3) | (c >> 2); 1448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convert6To8(int b) { 1488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int c = b & 0x3f; 1498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (c << 2) | (c >> 4); 1508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int divideBy255(int d) { 1548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (d + 128 + (d >> 8)) >> 8; 1558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convert8To4(int b) { 1598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int c = b & 0xff; 1608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return divideBy255(c * 15); 1618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convert8To5(int b) { 1658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int c = b & 0xff; 1668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return divideBy255(c * 31); 1678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int convertDiff(int base, int diff) { 1718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return convert5To8((0x1f & base) + kLookup[0x7 & diff]); 1728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 1738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 1748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 1758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, 1768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 low, bool second, bool flipped) { 1778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int baseX = 0; 1788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int baseY = 0; 1798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (second) { 1808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (flipped) { 1818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com baseY = 2; 1828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 1838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com baseX = 2; 1848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 1858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 1868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int i = 0; i < 8; i++) { 1878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int x, y; 1888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (flipped) { 1898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com x = baseX + (i >> 1); 1908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com y = baseY + (i & 1); 1918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 1928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com x = baseX + (i >> 2); 1938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com y = baseY + (i & 3); 1948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 1958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int k = y + (x * 4); 1968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); 1978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int delta = table[offset]; 1988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte* q = pOut + 3 * (x + 4 * y); 1998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = clamp(r + delta); 2008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = clamp(g + delta); 2018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = clamp(b + delta); 2028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 2048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Input is an ETC1 compressed version of the data. 2068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Output is a 4 x 4 square of 3-byte pixels in form R, G, B 2078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { 2098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; 2108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; 2118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r1, r2, g1, g2, b1, b2; 2128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (high & 2) { 2138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com // differential 2148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int rBase = high >> 27; 2158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int gBase = high >> 19; 2168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int bBase = high >> 11; 2178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r1 = convert5To8(rBase); 2188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r2 = convertDiff(rBase, high >> 24); 2198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g1 = convert5To8(gBase); 2208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g2 = convertDiff(gBase, high >> 16); 2218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b1 = convert5To8(bBase); 2228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b2 = convertDiff(bBase, high >> 8); 2238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 2248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com // not differential 2258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r1 = convert4To8(high >> 28); 2268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r2 = convert4To8(high >> 24); 2278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g1 = convert4To8(high >> 20); 2288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g2 = convert4To8(high >> 16); 2298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b1 = convert4To8(high >> 12); 2308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b2 = convert4To8(high >> 8); 2318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int tableIndexA = 7 & (high >> 5); 2338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int tableIndexB = 7 & (high >> 2); 2348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const int* tableA = kModifierTable + tableIndexA * 4; 2358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const int* tableB = kModifierTable + tableIndexB * 4; 2368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bool flipped = (high & 1) != 0; 2378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); 2388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); 2398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 2408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comtypedef struct { 2428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 high; 2438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 low; 2448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 score; // Lower is more accurate 2458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} etc_compressed; 2468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 2488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline void take_best(etc_compressed* a, const etc_compressed* b) { 2498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (a->score > b->score) { 2508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *a = *b; 2518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 2538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 2558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, 2568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte* pColors, bool flipped, bool second) { 2578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r = 0; 2588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g = 0; 2598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b = 0; 2608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 2618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (flipped) { 2628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int by = 0; 2638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (second) { 2648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com by = 2; 2658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int y = 0; y < 2; y++) { 2678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int yy = by + y; 2688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int x = 0; x < 4; x++) { 2698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int i = x + 4 * yy; 2708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (inMask & (1 << i)) { 2718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* p = pIn + i * 3; 2728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r += *(p++); 2738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g += *(p++); 2748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b += *(p++); 2758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 2798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int bx = 0; 2808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (second) { 2818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bx = 2; 2828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int y = 0; y < 4; y++) { 2848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int x = 0; x < 2; x++) { 2858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int xx = bx + x; 2868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int i = xx + 4 * y; 2878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (inMask & (1 << i)) { 2888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* p = pIn + i * 3; 2898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r += *(p++); 2908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g += *(p++); 2918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b += *(p++); 2928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 2968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pColors[0] = (etc1_byte)((r + 4) >> 3); 2978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pColors[1] = (etc1_byte)((g + 4) >> 3); 2988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pColors[2] = (etc1_byte)((b + 4) >> 3); 2998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 3008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 3028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cominline int square(int x) { 3038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return x * x; 3048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 3058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, 3078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, 3088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const int* pModifierTable) { 3098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 bestScore = ~0; 3108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int bestIndex = 0; 3118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int pixelR = pIn[0]; 3128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int pixelG = pIn[1]; 3138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int pixelB = pIn[2]; 3148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r = pBaseColors[0]; 3158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g = pBaseColors[1]; 3168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b = pBaseColors[2]; 3178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int i = 0; i < 4; i++) { 3188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int modifier = pModifierTable[i]; 3198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int decodedG = clamp(g + modifier); 3208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); 3218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (score >= bestScore) { 3228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com continue; 3238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int decodedR = clamp(r + modifier); 3258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com score += (etc1_uint32) (3 * square(decodedR - pixelR)); 3268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (score >= bestScore) { 3278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com continue; 3288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int decodedB = clamp(b + modifier); 3308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com score += (etc1_uint32) square(decodedB - pixelB); 3318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (score < bestScore) { 3328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bestScore = score; 3338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bestIndex = i; 3348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) 3378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com << bitIndex; 3388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *pLow |= lowMask; 3398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return bestScore; 3408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 3418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 3438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, 3448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_compressed* pCompressed, bool flipped, bool second, 3458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* pBaseColors, const int* pModifierTable) { 3468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int score = pCompressed->score; 3478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (flipped) { 3488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int by = 0; 3498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (second) { 3508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com by = 2; 3518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int y = 0; y < 2; y++) { 3538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int yy = by + y; 3548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int x = 0; x < 4; x++) { 3558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int i = x + 4 * yy; 3568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (inMask & (1 << i)) { 3578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com score += chooseModifier(pBaseColors, pIn + i * 3, 3588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com &pCompressed->low, yy + x * 4, pModifierTable); 3598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 3638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int bx = 0; 3648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (second) { 3658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bx = 2; 3668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int y = 0; y < 4; y++) { 3688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int x = 0; x < 2; x++) { 3698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int xx = bx + x; 3708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int i = xx + 4 * y; 3718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (inMask & (1 << i)) { 3728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com score += chooseModifier(pBaseColors, pIn + i * 3, 3738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com &pCompressed->low, y + xx * 4, pModifierTable); 3748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 3788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->score = score; 3798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 3808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic bool inRange4bitSigned(int color) { 3828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return color >= -4 && color <= 3; 3838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 3848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic void etc_encodeBaseColors(etc1_byte* pBaseColors, 3868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* pColors, etc_compressed* pCompressed) { 3878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks 3888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com bool differential; 3898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com { 3908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r51 = convert8To5(pColors[0]); 3918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g51 = convert8To5(pColors[1]); 3928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b51 = convert8To5(pColors[2]); 3938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r52 = convert8To5(pColors[3]); 3948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g52 = convert8To5(pColors[4]); 3958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b52 = convert8To5(pColors[5]); 3968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 3978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r1 = convert5To8(r51); 3988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g1 = convert5To8(g51); 3998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b1 = convert5To8(b51); 4008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int dr = r52 - r51; 4028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int dg = g52 - g51; 4038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int db = b52 - b51; 4048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) 4068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com && inRange4bitSigned(db); 4078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (differential) { 4088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r2 = convert5To8(r51 + dr); 4098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g2 = convert5To8(g51 + dg); 4108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b2 = convert5To8(b51 + db); 4118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) 4128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; 4138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (!differential) { 4178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r41 = convert8To4(pColors[0]); 4188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g41 = convert8To4(pColors[1]); 4198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b41 = convert8To4(pColors[2]); 4208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int r42 = convert8To4(pColors[3]); 4218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int g42 = convert8To4(pColors[4]); 4228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int b42 = convert8To4(pColors[5]); 4238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r1 = convert4To8(r41); 4248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g1 = convert4To8(g41); 4258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b1 = convert4To8(b41); 4268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com r2 = convert4To8(r42); 4278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com g2 = convert4To8(g42); 4288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com b2 = convert4To8(b42); 4298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 4308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com << 16) | (b41 << 12) | (b42 << 8); 4318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[0] = r1; 4338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[1] = g1; 4348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[2] = b1; 4358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[3] = r2; 4368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[4] = g2; 4378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors[5] = b2; 4388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 4398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic 4418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, 4428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { 4438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->score = ~0; 4448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->high = (flipped ? 1 : 0); 4458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pCompressed->low = 0; 4468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte pBaseColors[6]; 4488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_encodeBaseColors(pBaseColors, pColors, pCompressed); 4508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int originalHigh = pCompressed->high; 4528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const int* pModifierTable = kModifierTable; 4548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int i = 0; i < 8; i++, pModifierTable += 4) { 4558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_compressed temp; 4568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.score = 0; 4578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.high = originalHigh | (i << 5); 4588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.low = 0; 4598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, 4608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors, pModifierTable); 4618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com take_best(pCompressed, &temp); 4628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pModifierTable = kModifierTable; 4648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_compressed firstHalf = *pCompressed; 4658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (int i = 0; i < 8; i++, pModifierTable += 4) { 4668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_compressed temp; 4678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.score = firstHalf.score; 4688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.high = firstHalf.high | (i << 2); 4698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com temp.low = firstHalf.low; 4708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, 4718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pBaseColors + 3, pModifierTable); 4728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (i == 0) { 4738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *pCompressed = temp; 4748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 4758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com take_best(pCompressed, &temp); 4768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 4788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 4798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { 4818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[0] = (etc1_byte)(d >> 24); 4828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[1] = (etc1_byte)(d >> 16); 4838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[2] = (etc1_byte)(d >> 8); 4848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[3] = (etc1_byte) d; 4858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 4868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Input is a 4 x 4 square of 3-byte pixels in form R, G, B 4888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) 4898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pixel is valid or not. Invalid pixel color values are ignored when compressing. 4908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Output is an ETC1 compressed version of the data. 4918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 4928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, 4938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte* pOut) { 4948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte colors[6]; 4958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte flippedColors[6]; 4968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_average_colors_subblock(pIn, inMask, colors, false, false); 4978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); 4988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); 4998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); 5008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_compressed a, b; 5028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_encode_block_helper(pIn, inMask, colors, &a, false); 5038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); 5048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com take_best(&a, &b); 5058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBigEndian(pOut, a.high); 5068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBigEndian(pOut + 4, a.low); 5078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 5088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Return the size of the encoded image data (does not include size of PKM header). 5108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cometc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { 5128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; 5138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 5148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Encode an entire image. 5168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pIn - pointer to the image data. Formatted such that the Red component of 5178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; 5188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pOut - pointer to encoded data. Must be large enough to store entire encoded image. 5198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comint etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, 5218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { 5228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (pixelSize < 2 || pixelSize > 3) { 5238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return -1; 5248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; 5268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, 5278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 0xffff }; 5288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 5298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; 5308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedWidth = (width + 3) & ~3; 5328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedHeight = (height + 3) & ~3; 5338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 5358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 yEnd = height - y; 5368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (yEnd > 4) { 5378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com yEnd = 4; 5388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int ymask = kYMask[yEnd]; 5408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 5418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 xEnd = width - x; 5428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (xEnd > 4) { 5438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com xEnd = 4; 5448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int mask = ymask & kXMask[xEnd]; 5468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 5478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte* q = block + (cy * 4) * 3; 5488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); 5498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (pixelSize == 3) { 5508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com memcpy(q, p, xEnd * 3); 5518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 5528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 5538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com int pixel = (p[1] << 8) | p[0]; 5548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = convert5To8(pixel >> 11); 5558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = convert6To8(pixel >> 5); 5568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *q++ = convert5To8(pixel); 5578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com p += pixelSize; 5588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_encode_block(block, mask, encoded); 5628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com memcpy(pOut, encoded, sizeof(encoded)); 5638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut += sizeof(encoded); 5648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return 0; 5678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 5688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Decode an entire image. 5708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pIn - pointer to encoded data. 5718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pOut - pointer to the image data. Will be written such that the Red component of 5728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be 5738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// large enough to store entire image. 5748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comint etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, 5778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 width, etc1_uint32 height, 5788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 pixelSize, etc1_uint32 stride) { 5798cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (pixelSize < 2 || pixelSize > 3) { 5808cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return -1; 5818cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5828cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 5838cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5848cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedWidth = (width + 3) & ~3; 5858cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedHeight = (height + 3) & ~3; 5868cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 5878cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 5888cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 yEnd = height - y; 5898cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (yEnd > 4) { 5908cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com yEnd = 4; 5918cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5928cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 5938cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 xEnd = width - x; 5948cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (xEnd > 4) { 5958cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com xEnd = 4; 5968cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 5978cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_decode_block(pIn, block); 5988cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pIn += ETC1_ENCODED_BLOCK_SIZE; 5998cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 6008cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com const etc1_byte* q = block + (cy * 4) * 3; 6018cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); 6028cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (pixelSize == 3) { 6038cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com memcpy(p, q, xEnd * 3); 6048cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } else { 6058cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 6068cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte r = *q++; 6078cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte g = *q++; 6088cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_byte b = *q++; 6098cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 6108cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *p++ = (etc1_byte) pixel; 6118cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com *p++ = (etc1_byte) (pixel >> 8); 6128cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6138cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6148cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6158cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6168cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6178cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return 0; 6188cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6198cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6208cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; 6218cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6228cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; 6238cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; 6248cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; 6258cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; 6268cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; 6278cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6288cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; 6298cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6308cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { 6318cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[0] = (etc1_byte) (data >> 8); 6328cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com pOut[1] = (etc1_byte) data; 6338cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6348cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6358cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comstatic etc1_uint32 readBEUint16(const etc1_byte* pIn) { 6368cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return (pIn[0] << 8) | pIn[1]; 6378cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6388cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6398cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Format a PKM header 6408cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6418cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.comvoid etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { 6428cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com memcpy(pHeader, kMagic, sizeof(kMagic)); 6438cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedWidth = (width + 3) & ~3; 6448cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedHeight = (height + 3) & ~3; 6458cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); 6468cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); 6478cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); 6488cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); 6498cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); 6508cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6518cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6528cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Check if a PKM header is correctly formatted. 6538cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6548cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cometc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { 6558cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com if (memcmp(pHeader, kMagic, sizeof(kMagic))) { 6568cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return false; 6578cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com } 6588cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); 6598cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); 6608cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); 6618cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 6628cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 6638cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return format == ETC1_RGB_NO_MIPMAPS && 6648cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com encodedWidth >= width && encodedWidth - width < 4 && 6658cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com encodedHeight >= height && encodedHeight - height < 4; 6668cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6678cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6688cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Read the image width from a PKM header 6698cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6708cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cometc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { 6718cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 6728cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 6738cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6748cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com// Read the image height from a PKM header 6758cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com 6768cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.cometc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ 6778cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 6788cf81e0f4fa2a8054ac4cea1e7490028809cb893robertphillips@google.com} 679