1a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Copyright 2009 Google Inc. 2a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// 3a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Licensed under the Apache License, Version 2.0 (the "License"); 4a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// you may not use this file except in compliance with the License. 5a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// You may obtain a copy of the License at 6a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// 7a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// http://www.apache.org/licenses/LICENSE-2.0 8a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// 9a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Unless required by applicable law or agreed to in writing, software 10a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// distributed under the License is distributed on an "AS IS" BASIS, 11a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// See the License for the specific language governing permissions and 13a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// limitations under the License. 14a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 15a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich#include <ETC1/etc1.h> 16a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 17a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich#include <string.h> 18a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 19a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt 20a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 21a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich The number of bits that represent a 4x4 texel block is 64 bits if 22a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich <internalformat> is given by ETC1_RGB8_OES. 23a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 24a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich The data for a block is a number of bytes, 25a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 26a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich {q0, q1, q2, q3, q4, q5, q6, q7} 27a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 28a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich where byte q0 is located at the lowest memory address and q7 at 29a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich the highest. The 64 bits specifying the block is then represented 30a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich by the following 64 bit integer: 31a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 32a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; 33a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 34a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ETC1_RGB8_OES: 35a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 36a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich a) bit layout in bits 63 through 32 if diffbit = 0 37a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 38a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 39a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 40a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | base col1 | base col2 | base col1 | base col2 | 41a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| 42a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 43a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 44a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 45a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich --------------------------------------------------- 46a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | base col1 | base col2 | table | table |diff|flip| 47a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | 48a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich --------------------------------------------------- 49a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 50a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 51a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b) bit layout in bits 63 through 32 if diffbit = 1 52a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 53a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 54a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 55a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | base col1 | dcol 2 | base col1 | dcol 2 | 56a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | 57a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 58a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 59a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 60a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich --------------------------------------------------- 61a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | base col 1 | dcol 2 | table | table |diff|flip| 62a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | 63a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich --------------------------------------------------- 64a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 65a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 66a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich c) bit layout in bits 31 through 0 (in both cases) 67a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 68a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 69a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 70a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | most significant pixel index bits | 71a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| 72a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----------------------------------------------- 73a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 74a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 75a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich -------------------------------------------------- 76a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | least significant pixel index bits | 77a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | 78a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich -------------------------------------------------- 79a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 80a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 81a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: 82a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 83a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich table codeword modifier table 84a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ------------------ ---------------------- 85a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 0 -8 -2 2 8 86a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 1 -17 -5 5 17 87a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 2 -29 -9 9 29 88a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 3 -42 -13 13 42 89a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 4 -60 -18 18 60 90a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 5 -80 -24 24 80 91a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 6 -106 -33 33 106 92a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 7 -183 -47 47 183 93a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 94a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 95a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich Add table 3.17.3 Mapping from pixel index values to modifier values for 96a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ETC1 compressed textures: 97a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 98a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pixel index value 99a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich --------------- 100a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich msb lsb resulting modifier value 101a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich ----- ----- ------------------------- 102a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 1 1 -b (large negative value) 103a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 1 0 -a (small negative value) 104a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 0 0 a (small positive value) 105a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 0 1 b (large positive value) 106a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 107a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 108a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich */ 109a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 110a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const int kModifierTable[] = { 111a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 0 */2, 8, -2, -8, 112a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 1 */5, 17, -5, -17, 113a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 2 */9, 29, -9, -29, 114a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 3 */13, 42, -13, -42, 115a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 4 */18, 60, -18, -60, 116a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 5 */24, 80, -24, -80, 117a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 6 */33, 106, -33, -106, 118a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/* 7 */47, 183, -47, -183 }; 119a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 120a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; 121a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 122a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic inline etc1_byte clamp(int x) { 123a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); 124a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 125a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 126a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 127a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convert4To8(int b) { 128a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int c = b & 0xf; 129a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (c << 4) | c; 130a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 131a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 132a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 133a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convert5To8(int b) { 134a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int c = b & 0x1f; 135a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (c << 3) | (c >> 2); 136a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 137a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 138a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 139a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convert6To8(int b) { 140a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int c = b & 0x3f; 141a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (c << 2) | (c >> 4); 142a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 143a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 144a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 145a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int divideBy255(int d) { 146a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (d + 128 + (d >> 8)) >> 8; 147a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 148a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 149a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 150a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convert8To4(int b) { 151a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int c = b & 0xff; 152a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return divideBy255(b * 15); 153a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 154a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 155a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 156a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convert8To5(int b) { 157a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int c = b & 0xff; 158a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return divideBy255(b * 31); 159a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 160a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 161a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 162a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int convertDiff(int base, int diff) { 163a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return convert5To8((0x1f & base) + kLookup[0x7 & diff]); 164a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 165a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 166a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 167a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, 168a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 low, bool second, bool flipped) { 169a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int baseX = 0; 170a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int baseY = 0; 171a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (second) { 172a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (flipped) { 173a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich baseY = 2; 174a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 175a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich baseX = 2; 176a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 177a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 178a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int i = 0; i < 8; i++) { 179a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int x, y; 180a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (flipped) { 181a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich x = baseX + (i >> 1); 182a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich y = baseY + (i & 1); 183a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 184a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich x = baseX + (i >> 2); 185a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich y = baseY + (i & 3); 186a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 187a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int k = y + (x * 4); 188a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); 189a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int delta = table[offset]; 190a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte* q = pOut + 3 * (x + 4 * y); 191a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = clamp(r + delta); 192a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = clamp(g + delta); 193a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = clamp(b + delta); 194a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 195a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 196a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 197a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Input is an ETC1 compressed version of the data. 198a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Output is a 4 x 4 square of 3-byte pixels in form R, G, B 199a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 200a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { 201a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; 202a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; 203a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r1, r2, g1, g2, b1, b2; 204a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (high & 2) { 205a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich // differential 206a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int rBase = high >> 27; 207a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int gBase = high >> 19; 208a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int bBase = high >> 11; 209a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r1 = convert5To8(rBase); 210a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r2 = convertDiff(rBase, high >> 24); 211a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g1 = convert5To8(gBase); 212a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g2 = convertDiff(gBase, high >> 16); 213a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b1 = convert5To8(bBase); 214a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b2 = convertDiff(bBase, high >> 8); 215a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 216a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich // not differential 217a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r1 = convert4To8(high >> 28); 218a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r2 = convert4To8(high >> 24); 219a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g1 = convert4To8(high >> 20); 220a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g2 = convert4To8(high >> 16); 221a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b1 = convert4To8(high >> 12); 222a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b2 = convert4To8(high >> 8); 223a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 224a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int tableIndexA = 7 & (high >> 5); 225a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int tableIndexB = 7 & (high >> 2); 226a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const int* tableA = kModifierTable + tableIndexA * 4; 227a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const int* tableB = kModifierTable + tableIndexB * 4; 228a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bool flipped = (high & 1) != 0; 229a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); 230a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); 231a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 232a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 233a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichtypedef struct { 234a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 high; 235a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 low; 236a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 score; // Lower is more accurate 237a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} etc_compressed; 238a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 239a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 240a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline void take_best(etc_compressed* a, const etc_compressed* b) { 241a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (a->score > b->score) { 242a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *a = *b; 243a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 244a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 245a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 246a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 247a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, 248a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte* pColors, bool flipped, bool second) { 249a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r = 0; 250a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g = 0; 251a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b = 0; 252a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 253a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (flipped) { 254a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int by = 0; 255a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (second) { 256a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich by = 2; 257a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 258a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int y = 0; y < 2; y++) { 259a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int yy = by + y; 260a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int x = 0; x < 4; x++) { 261a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int i = x + 4 * yy; 262a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (inMask & (1 << i)) { 263a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* p = pIn + i * 3; 264a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r += *(p++); 265a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g += *(p++); 266a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b += *(p++); 267a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 268a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 269a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 270a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 271a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int bx = 0; 272a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (second) { 273a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bx = 2; 274a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 275a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int y = 0; y < 4; y++) { 276a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int x = 0; x < 2; x++) { 277a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int xx = bx + x; 278a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int i = xx + 4 * y; 279a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (inMask & (1 << i)) { 280a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* p = pIn + i * 3; 281a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r += *(p++); 282a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g += *(p++); 283a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b += *(p++); 284a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 285a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 286a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 287a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 288a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pColors[0] = (etc1_byte)((r + 4) >> 3); 289a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pColors[1] = (etc1_byte)((g + 4) >> 3); 290a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pColors[2] = (etc1_byte)((b + 4) >> 3); 291a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 292a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 293a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 294a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichinline int square(int x) { 295a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return x * x; 296a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 297a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 298a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, 299a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, 300a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const int* pModifierTable) { 301a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 bestScore = ~0; 302a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int bestIndex = 0; 303a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int pixelR = pIn[0]; 304a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int pixelG = pIn[1]; 305a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int pixelB = pIn[2]; 306a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r = pBaseColors[0]; 307a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g = pBaseColors[1]; 308a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b = pBaseColors[2]; 309a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int i = 0; i < 4; i++) { 310a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int modifier = pModifierTable[i]; 311a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int decodedG = clamp(g + modifier); 312a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); 313a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (score >= bestScore) { 314a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich continue; 315a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 316a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int decodedR = clamp(r + modifier); 317a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich score += (etc1_uint32) (3 * square(decodedR - pixelR)); 318a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (score >= bestScore) { 319a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich continue; 320a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 321a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int decodedB = clamp(b + modifier); 322a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich score += (etc1_uint32) square(decodedB - pixelB); 323a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (score < bestScore) { 324a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bestScore = score; 325a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bestIndex = i; 326a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 327a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 328a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) 329a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich << bitIndex; 330a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *pLow |= lowMask; 331a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return bestScore; 332a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 333a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 334a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 335a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, 336a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_compressed* pCompressed, bool flipped, bool second, 337a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* pBaseColors, const int* pModifierTable) { 338a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int score = pCompressed->score; 339a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (flipped) { 340a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int by = 0; 341a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (second) { 342a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich by = 2; 343a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 344a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int y = 0; y < 2; y++) { 345a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int yy = by + y; 346a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int x = 0; x < 4; x++) { 347a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int i = x + 4 * yy; 348a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (inMask & (1 << i)) { 349a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich score += chooseModifier(pBaseColors, pIn + i * 3, 350a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich &pCompressed->low, yy + x * 4, pModifierTable); 351a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 352a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 353a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 354a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 355a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int bx = 0; 356a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (second) { 357a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bx = 2; 358a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 359a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int y = 0; y < 4; y++) { 360a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int x = 0; x < 2; x++) { 361a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int xx = bx + x; 362a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int i = xx + 4 * y; 363a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (inMask & (1 << i)) { 364a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich score += chooseModifier(pBaseColors, pIn + i * 3, 365a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich &pCompressed->low, y + xx * 4, pModifierTable); 366a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 367a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 368a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 369a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 370a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->score = score; 371a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 372a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 373a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic bool inRange4bitSigned(int color) { 374a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return color >= -4 && color <= 3; 375a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 376a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 377a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic void etc_encodeBaseColors(etc1_byte* pBaseColors, 378a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* pColors, etc_compressed* pCompressed) { 379a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks 380a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich bool differential; 381a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich { 382a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r51 = convert8To5(pColors[0]); 383a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g51 = convert8To5(pColors[1]); 384a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b51 = convert8To5(pColors[2]); 385a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r52 = convert8To5(pColors[3]); 386a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g52 = convert8To5(pColors[4]); 387a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b52 = convert8To5(pColors[5]); 388a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 389a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r1 = convert5To8(r51); 390a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g1 = convert5To8(g51); 391a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b1 = convert5To8(b51); 392a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 393a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int dr = r52 - r51; 394a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int dg = g52 - g51; 395a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int db = b52 - b51; 396a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 397a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) 398a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich && inRange4bitSigned(db); 399a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (differential) { 400a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r2 = convert5To8(r51 + dr); 401a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g2 = convert5To8(g51 + dg); 402a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b2 = convert5To8(b51 + db); 403a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) 404a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; 405a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 406a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 407a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 408a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (!differential) { 409a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r41 = convert8To4(pColors[0]); 410a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g41 = convert8To4(pColors[1]); 411a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b41 = convert8To4(pColors[2]); 412a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int r42 = convert8To4(pColors[3]); 413a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int g42 = convert8To4(pColors[4]); 414a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int b42 = convert8To4(pColors[5]); 415a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r1 = convert4To8(r41); 416a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g1 = convert4To8(g41); 417a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b1 = convert4To8(b41); 418a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich r2 = convert4To8(r42); 419a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich g2 = convert4To8(g42); 420a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich b2 = convert4To8(b42); 421a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 422a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich << 16) | (b41 << 12) | (b42 << 8); 423a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 424a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[0] = r1; 425a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[1] = g1; 426a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[2] = b1; 427a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[3] = r2; 428a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[4] = g2; 429a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors[5] = b2; 430a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 431a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 432a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic 433a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, 434a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { 435a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->score = ~0; 436a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->high = (flipped ? 1 : 0); 437a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pCompressed->low = 0; 438a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 439a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte pBaseColors[6]; 440a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 441a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_encodeBaseColors(pBaseColors, pColors, pCompressed); 442a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 443a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int originalHigh = pCompressed->high; 444a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 445a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const int* pModifierTable = kModifierTable; 446a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int i = 0; i < 8; i++, pModifierTable += 4) { 447a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_compressed temp; 448a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.score = 0; 449a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.high = originalHigh | (i << 5); 450a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.low = 0; 451a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, 452a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors, pModifierTable); 453a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich take_best(pCompressed, &temp); 454a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 455a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pModifierTable = kModifierTable; 456a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_compressed firstHalf = *pCompressed; 457a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (int i = 0; i < 8; i++, pModifierTable += 4) { 458a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_compressed temp; 459a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.score = firstHalf.score; 460a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.high = firstHalf.high | (i << 2); 461a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich temp.low = firstHalf.low; 462a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, 463a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pBaseColors + 3, pModifierTable); 464a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (i == 0) { 465a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *pCompressed = temp; 466a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 467a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich take_best(pCompressed, &temp); 468a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 469a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 470a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 471a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 472a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { 473a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[0] = (etc1_byte)(d >> 24); 474a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[1] = (etc1_byte)(d >> 16); 475a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[2] = (etc1_byte)(d >> 8); 476a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[3] = (etc1_byte) d; 477a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 478a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 479a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Input is a 4 x 4 square of 3-byte pixels in form R, G, B 480a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) 481a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pixel is valid or not. Invalid pixel color values are ignored when compressing. 482a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Output is an ETC1 compressed version of the data. 483a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 484a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, 485a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte* pOut) { 486a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte colors[6]; 487a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte flippedColors[6]; 488a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_average_colors_subblock(pIn, inMask, colors, false, false); 489a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); 490a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); 491a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); 492a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 493a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_compressed a, b; 494a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_encode_block_helper(pIn, inMask, colors, &a, false); 495a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); 496a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich take_best(&a, &b); 497a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBigEndian(pOut, a.high); 498a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBigEndian(pOut + 4, a.low); 499a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 500a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 501a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Return the size of the encoded image data (does not include size of PKM header). 502a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 503a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichetc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { 504a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; 505a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 506a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 507a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Encode an entire image. 508a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pIn - pointer to the image data. Formatted such that the Red component of 509a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; 510a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pOut - pointer to encoded data. Must be large enough to store entire encoded image. 511a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 512a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichint etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, 513a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { 514a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (pixelSize < 2 || pixelSize > 3) { 515a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return -1; 516a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 517a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; 518a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, 519a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 0xffff }; 520a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 521a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; 522a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 523a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 524a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 525a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 526a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 527a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 yEnd = height - y; 528a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (yEnd > 4) { 529a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich yEnd = 4; 530a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 531a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int ymask = kYMask[yEnd]; 532a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 533a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 xEnd = width - x; 534a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (xEnd > 4) { 535a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich xEnd = 4; 536a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 537a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int mask = ymask & kXMask[xEnd]; 538a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 539a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte* q = block + (cy * 4) * 3; 540a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); 541a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (pixelSize == 3) { 542a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich memcpy(q, p, xEnd * 3); 543a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 544a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 545a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich int pixel = (p[1] << 8) | p[0]; 546a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = convert5To8(pixel >> 11); 547a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = convert6To8(pixel >> 5); 548a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *q++ = convert5To8(pixel); 549a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich p += pixelSize; 550a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 551a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 552a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 553a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_encode_block(block, mask, encoded); 554a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich memcpy(pOut, encoded, sizeof(encoded)); 555a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut += sizeof(encoded); 556a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 557a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 558a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return 0; 559a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 560a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 561a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Decode an entire image. 562a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pIn - pointer to encoded data. 563a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pOut - pointer to the image data. Will be written such that the Red component of 564a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be 565a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// large enough to store entire image. 566a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 567a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 568a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichint etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, 569a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 width, etc1_uint32 height, 570a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 pixelSize, etc1_uint32 stride) { 571a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (pixelSize < 2 || pixelSize > 3) { 572a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return -1; 573a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 574a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 575a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 576a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 577a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 578a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 579a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 580a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 yEnd = height - y; 581a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (yEnd > 4) { 582a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich yEnd = 4; 583a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 584a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 585a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 xEnd = width - x; 586a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (xEnd > 4) { 587a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich xEnd = 4; 588a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 589a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_decode_block(pIn, block); 590a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pIn += ETC1_ENCODED_BLOCK_SIZE; 591a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 592a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich const etc1_byte* q = block + (cy * 4) * 3; 593a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); 594a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (pixelSize == 3) { 595a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich memcpy(p, q, xEnd * 3); 596a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } else { 597a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 598a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte r = *q++; 599a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte g = *q++; 600a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_byte b = *q++; 601a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 602a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *p++ = (etc1_byte) pixel; 603a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *p++ = (etc1_byte) (pixel >> 8); 604a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 605a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 606a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 607a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 608a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 609a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return 0; 610a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 611a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 612a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; 613a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 614a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; 615a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; 616a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; 617a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; 618a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; 619a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 620a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; 621a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 622a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { 623a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[0] = (etc1_byte) (data >> 8); 624a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich pOut[1] = (etc1_byte) data; 625a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 626a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 627a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichstatic etc1_uint32 readBEUint16(const etc1_byte* pIn) { 628a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return (pIn[0] << 8) | pIn[1]; 629a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 630a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 631a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Format a PKM header 632a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 633a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { 634a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich memcpy(pHeader, kMagic, sizeof(kMagic)); 635a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 636a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 637a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); 638a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); 639a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); 640a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); 641a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); 642a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 643a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 644a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Check if a PKM header is correctly formatted. 645a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 646a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichetc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { 647a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich if (memcmp(pHeader, kMagic, sizeof(kMagic))) { 648a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return false; 649a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich } 650a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); 651a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); 652a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); 653a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 654a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 655a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return format == ETC1_RGB_NO_MIPMAPS && 656a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich encodedWidth >= width && encodedWidth - width < 4 && 657a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich encodedHeight >= height && encodedHeight - height < 4; 658a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 659a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 660a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Read the image width from a PKM header 661a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 662a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichetc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { 663a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 664a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 665a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 666a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich// Read the image height from a PKM header 667a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich 668a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichetc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ 669a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 670a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich} 671