101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Copyright 2009 Google Inc. 201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// 301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Licensed under the Apache License, Version 2.0 (the "License"); 401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// you may not use this file except in compliance with the License. 501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// You may obtain a copy of the License at 601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// 701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// http://www.apache.org/licenses/LICENSE-2.0 801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// 901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Unless required by applicable law or agreed to in writing, software 1001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// distributed under the License is distributed on an "AS IS" BASIS, 1101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// See the License for the specific language governing permissions and 1301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// limitations under the License. 1401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich#include <ETC1/etc1.h> 1601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich#include <string.h> 1801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt 2001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 2101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich The number of bits that represent a 4x4 texel block is 64 bits if 2201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich <internalformat> is given by ETC1_RGB8_OES. 2301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 2401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich The data for a block is a number of bytes, 2501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 2601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich {q0, q1, q2, q3, q4, q5, q6, q7} 2701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 2801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich where byte q0 is located at the lowest memory address and q7 at 2901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich the highest. The 64 bits specifying the block is then represented 3001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich by the following 64 bit integer: 3101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 3201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7; 3301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 3401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ETC1_RGB8_OES: 3501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 3601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich a) bit layout in bits 63 through 32 if diffbit = 0 3701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 3801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 3901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 4001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | base col1 | base col2 | base col1 | base col2 | 4101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| 4201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 4301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 4401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 4501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich --------------------------------------------------- 4601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | base col1 | base col2 | table | table |diff|flip| 4701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | 4801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich --------------------------------------------------- 4901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 5001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 5101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b) bit layout in bits 63 through 32 if diffbit = 1 5201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 5301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 5401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 5501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | base col1 | dcol 2 | base col1 | dcol 2 | 5601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | 5701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 5801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 5901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 6001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich --------------------------------------------------- 6101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | base col 1 | dcol 2 | table | table |diff|flip| 6201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | 6301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich --------------------------------------------------- 6401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 6501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 6601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich c) bit layout in bits 31 through 0 (in both cases) 6701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 6801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 6901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 7001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | most significant pixel index bits | 7101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| 7201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----------------------------------------------- 7301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 7401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 7501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich -------------------------------------------------- 7601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | least significant pixel index bits | 7701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | 7801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich -------------------------------------------------- 7901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 8001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 8101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures: 8201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 8301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich table codeword modifier table 8401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ------------------ ---------------------- 8501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 0 -8 -2 2 8 8601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1 -17 -5 5 17 8701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 2 -29 -9 9 29 8801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 3 -42 -13 13 42 8901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 4 -60 -18 18 60 9001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 5 -80 -24 24 80 9101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 6 -106 -33 33 106 9201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 7 -183 -47 47 183 9301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 9401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 9501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich Add table 3.17.3 Mapping from pixel index values to modifier values for 9601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ETC1 compressed textures: 9701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 9801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pixel index value 9901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich --------------- 10001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich msb lsb resulting modifier value 10101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich ----- ----- ------------------------- 10201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1 1 -b (large negative value) 10301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 1 0 -a (small negative value) 10401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 0 0 a (small positive value) 10501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 0 1 b (large positive value) 10601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 10701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 10801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich */ 10901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 11001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const int kModifierTable[] = { 11101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 0 */2, 8, -2, -8, 11201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 1 */5, 17, -5, -17, 11301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 2 */9, 29, -9, -29, 11401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 3 */13, 42, -13, -42, 11501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 4 */18, 60, -18, -60, 11601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 5 */24, 80, -24, -80, 11701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 6 */33, 106, -33, -106, 11801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich/* 7 */47, 183, -47, -183 }; 11901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 12001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 }; 12101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 12201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic inline etc1_byte clamp(int x) { 12301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0); 12401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 12501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 12601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 12701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convert4To8(int b) { 12801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int c = b & 0xf; 12901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (c << 4) | c; 13001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 13101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 13201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 13301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convert5To8(int b) { 13401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int c = b & 0x1f; 13501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (c << 3) | (c >> 2); 13601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 13701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 13801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 13901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convert6To8(int b) { 14001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int c = b & 0x3f; 14101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (c << 2) | (c >> 4); 14201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 14301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 14401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 14501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int divideBy255(int d) { 14601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (d + 128 + (d >> 8)) >> 8; 14701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 14801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 14901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 15001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convert8To4(int b) { 15101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int c = b & 0xff; 1522b93f0bf448160b002dec10c5bb1c9985a5950e6Jack Palevich return divideBy255(c * 15); 15301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 15401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 15501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 15601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convert8To5(int b) { 15701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int c = b & 0xff; 1582b93f0bf448160b002dec10c5bb1c9985a5950e6Jack Palevich return divideBy255(c * 31); 15901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 16001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 16101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 16201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int convertDiff(int base, int diff) { 16301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return convert5To8((0x1f & base) + kLookup[0x7 & diff]); 16401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 16501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 16601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 16701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table, 16801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 low, bool second, bool flipped) { 16901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int baseX = 0; 17001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int baseY = 0; 17101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (second) { 17201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (flipped) { 17301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich baseY = 2; 17401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 17501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich baseX = 2; 17601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 17701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 17801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int i = 0; i < 8; i++) { 17901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int x, y; 18001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (flipped) { 18101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich x = baseX + (i >> 1); 18201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich y = baseY + (i & 1); 18301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 18401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich x = baseX + (i >> 2); 18501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich y = baseY + (i & 3); 18601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 18701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int k = y + (x * 4); 18801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2); 18901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int delta = table[offset]; 19001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte* q = pOut + 3 * (x + 4 * y); 19101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = clamp(r + delta); 19201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = clamp(g + delta); 19301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = clamp(b + delta); 19401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 19501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 19601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 19701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Input is an ETC1 compressed version of the data. 19801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Output is a 4 x 4 square of 3-byte pixels in form R, G, B 19901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 20001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) { 20101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; 20201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7]; 20301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r1, r2, g1, g2, b1, b2; 20401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (high & 2) { 20501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich // differential 20601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int rBase = high >> 27; 20701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int gBase = high >> 19; 20801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int bBase = high >> 11; 20901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r1 = convert5To8(rBase); 21001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r2 = convertDiff(rBase, high >> 24); 21101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g1 = convert5To8(gBase); 21201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g2 = convertDiff(gBase, high >> 16); 21301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b1 = convert5To8(bBase); 21401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b2 = convertDiff(bBase, high >> 8); 21501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 21601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich // not differential 21701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r1 = convert4To8(high >> 28); 21801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r2 = convert4To8(high >> 24); 21901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g1 = convert4To8(high >> 20); 22001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g2 = convert4To8(high >> 16); 22101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b1 = convert4To8(high >> 12); 22201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b2 = convert4To8(high >> 8); 22301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 22401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int tableIndexA = 7 & (high >> 5); 22501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int tableIndexB = 7 & (high >> 2); 22601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const int* tableA = kModifierTable + tableIndexA * 4; 22701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const int* tableB = kModifierTable + tableIndexB * 4; 22801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bool flipped = (high & 1) != 0; 22901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped); 23001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped); 23101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 23201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 23301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichtypedef struct { 23401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 high; 23501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 low; 23601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 score; // Lower is more accurate 23701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} etc_compressed; 23801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 23901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 24001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline void take_best(etc_compressed* a, const etc_compressed* b) { 24101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (a->score > b->score) { 24201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *a = *b; 24301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 24401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 24501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 24601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 24701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask, 24801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte* pColors, bool flipped, bool second) { 24901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r = 0; 25001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g = 0; 25101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b = 0; 25201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 25301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (flipped) { 25401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int by = 0; 25501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (second) { 25601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich by = 2; 25701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 25801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int y = 0; y < 2; y++) { 25901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int yy = by + y; 26001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int x = 0; x < 4; x++) { 26101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int i = x + 4 * yy; 26201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (inMask & (1 << i)) { 26301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* p = pIn + i * 3; 26401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r += *(p++); 26501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g += *(p++); 26601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b += *(p++); 26701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 26801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 26901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 27001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 27101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int bx = 0; 27201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (second) { 27301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bx = 2; 27401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 27501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int y = 0; y < 4; y++) { 27601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int x = 0; x < 2; x++) { 27701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int xx = bx + x; 27801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int i = xx + 4 * y; 27901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (inMask & (1 << i)) { 28001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* p = pIn + i * 3; 28101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r += *(p++); 28201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g += *(p++); 28301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b += *(p++); 28401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 28501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 28601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 28701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 28801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pColors[0] = (etc1_byte)((r + 4) >> 3); 28901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pColors[1] = (etc1_byte)((g + 4) >> 3); 29001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pColors[2] = (etc1_byte)((b + 4) >> 3); 29101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 29201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 29301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 29401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichinline int square(int x) { 29501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return x * x; 29601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 29701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 29801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic etc1_uint32 chooseModifier(const etc1_byte* pBaseColors, 29901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex, 30001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const int* pModifierTable) { 30101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 bestScore = ~0; 30201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int bestIndex = 0; 30301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int pixelR = pIn[0]; 30401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int pixelG = pIn[1]; 30501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int pixelB = pIn[2]; 30601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r = pBaseColors[0]; 30701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g = pBaseColors[1]; 30801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b = pBaseColors[2]; 30901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int i = 0; i < 4; i++) { 31001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int modifier = pModifierTable[i]; 31101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int decodedG = clamp(g + modifier); 31201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG)); 31301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (score >= bestScore) { 31401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich continue; 31501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 31601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int decodedR = clamp(r + modifier); 31701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich score += (etc1_uint32) (3 * square(decodedR - pixelR)); 31801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (score >= bestScore) { 31901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich continue; 32001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 32101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int decodedB = clamp(b + modifier); 32201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich score += (etc1_uint32) square(decodedB - pixelB); 32301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (score < bestScore) { 32401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bestScore = score; 32501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bestIndex = i; 32601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 32701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 32801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1)) 32901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich << bitIndex; 33001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *pLow |= lowMask; 33101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return bestScore; 33201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 33301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 33401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 33501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask, 33601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_compressed* pCompressed, bool flipped, bool second, 33701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* pBaseColors, const int* pModifierTable) { 33801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int score = pCompressed->score; 33901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (flipped) { 34001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int by = 0; 34101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (second) { 34201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich by = 2; 34301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 34401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int y = 0; y < 2; y++) { 34501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int yy = by + y; 34601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int x = 0; x < 4; x++) { 34701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int i = x + 4 * yy; 34801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (inMask & (1 << i)) { 34901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich score += chooseModifier(pBaseColors, pIn + i * 3, 35001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich &pCompressed->low, yy + x * 4, pModifierTable); 35101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 35201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 35301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 35401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 35501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int bx = 0; 35601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (second) { 35701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bx = 2; 35801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 35901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int y = 0; y < 4; y++) { 36001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int x = 0; x < 2; x++) { 36101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int xx = bx + x; 36201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int i = xx + 4 * y; 36301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (inMask & (1 << i)) { 36401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich score += chooseModifier(pBaseColors, pIn + i * 3, 36501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich &pCompressed->low, y + xx * 4, pModifierTable); 36601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 36701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 36801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 36901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 37001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->score = score; 37101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 37201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 37301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic bool inRange4bitSigned(int color) { 37401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return color >= -4 && color <= 3; 37501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 37601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 37701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic void etc_encodeBaseColors(etc1_byte* pBaseColors, 37801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* pColors, etc_compressed* pCompressed) { 37901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks 38001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich bool differential; 38101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich { 38201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r51 = convert8To5(pColors[0]); 38301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g51 = convert8To5(pColors[1]); 38401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b51 = convert8To5(pColors[2]); 38501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r52 = convert8To5(pColors[3]); 38601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g52 = convert8To5(pColors[4]); 38701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b52 = convert8To5(pColors[5]); 38801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 38901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r1 = convert5To8(r51); 39001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g1 = convert5To8(g51); 39101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b1 = convert5To8(b51); 39201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 39301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int dr = r52 - r51; 39401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int dg = g52 - g51; 39501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int db = b52 - b51; 39601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 39701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich differential = inRange4bitSigned(dr) && inRange4bitSigned(dg) 39801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich && inRange4bitSigned(db); 39901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (differential) { 40001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r2 = convert5To8(r51 + dr); 40101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g2 = convert5To8(g51 + dg); 40201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b2 = convert5To8(b51 + db); 40301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19) 40401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2; 40501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 40601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 40701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 40801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (!differential) { 40901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r41 = convert8To4(pColors[0]); 41001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g41 = convert8To4(pColors[1]); 41101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b41 = convert8To4(pColors[2]); 41201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int r42 = convert8To4(pColors[3]); 41301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int g42 = convert8To4(pColors[4]); 41401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int b42 = convert8To4(pColors[5]); 41501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r1 = convert4To8(r41); 41601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g1 = convert4To8(g41); 41701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b1 = convert4To8(b41); 41801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich r2 = convert4To8(r42); 41901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich g2 = convert4To8(g42); 42001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich b2 = convert4To8(b42); 42101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42 42201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich << 16) | (b41 << 12) | (b42 << 8); 42301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 42401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[0] = r1; 42501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[1] = g1; 42601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[2] = b1; 42701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[3] = r2; 42801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[4] = g2; 42901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors[5] = b2; 43001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 43101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 43201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic 43301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask, 43401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) { 43501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->score = ~0; 43601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->high = (flipped ? 1 : 0); 43701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pCompressed->low = 0; 43801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 43901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte pBaseColors[6]; 44001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 44101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_encodeBaseColors(pBaseColors, pColors, pCompressed); 44201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 44301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int originalHigh = pCompressed->high; 44401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 44501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const int* pModifierTable = kModifierTable; 44601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int i = 0; i < 8; i++, pModifierTable += 4) { 44701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_compressed temp; 44801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.score = 0; 44901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.high = originalHigh | (i << 5); 45001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.low = 0; 45101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false, 45201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors, pModifierTable); 45301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich take_best(pCompressed, &temp); 45401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 45501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pModifierTable = kModifierTable; 45601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_compressed firstHalf = *pCompressed; 45701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (int i = 0; i < 8; i++, pModifierTable += 4) { 45801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_compressed temp; 45901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.score = firstHalf.score; 46001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.high = firstHalf.high | (i << 2); 46101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich temp.low = firstHalf.low; 46201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true, 46301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pBaseColors + 3, pModifierTable); 46401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (i == 0) { 46501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *pCompressed = temp; 46601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 46701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich take_best(pCompressed, &temp); 46801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 46901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 47001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 47101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 47201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) { 47301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[0] = (etc1_byte)(d >> 24); 47401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[1] = (etc1_byte)(d >> 16); 47501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[2] = (etc1_byte)(d >> 8); 47601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[3] = (etc1_byte) d; 47701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 47801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 47901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Input is a 4 x 4 square of 3-byte pixels in form R, G, B 48001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y) 48101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pixel is valid or not. Invalid pixel color values are ignored when compressing. 48201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Output is an ETC1 compressed version of the data. 48301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 48401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc1_encode_block(const etc1_byte* pIn, etc1_uint32 inMask, 48501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte* pOut) { 48601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte colors[6]; 48701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte flippedColors[6]; 48801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_average_colors_subblock(pIn, inMask, colors, false, false); 48901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_average_colors_subblock(pIn, inMask, colors + 3, false, true); 49001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_average_colors_subblock(pIn, inMask, flippedColors, true, false); 49101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true); 49201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 49301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_compressed a, b; 49401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_encode_block_helper(pIn, inMask, colors, &a, false); 49501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc_encode_block_helper(pIn, inMask, flippedColors, &b, true); 49601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich take_best(&a, &b); 49701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBigEndian(pOut, a.high); 49801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBigEndian(pOut + 4, a.low); 49901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 50001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 50101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Return the size of the encoded image data (does not include size of PKM header). 50201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 50301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichetc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) { 50401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; 50501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 50601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 50701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Encode an entire image. 50801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pIn - pointer to the image data. Formatted such that the Red component of 50901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset; 51001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pOut - pointer to encoded data. Must be large enough to store entire encoded image. 51101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 51201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichint etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height, 51301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) { 51401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (pixelSize < 2 || pixelSize > 3) { 51501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return -1; 51601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 51701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff }; 51801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777, 51901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 0xffff }; 52001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 52101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE]; 52201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 52301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 52401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 52501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 52601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 52701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 yEnd = height - y; 52801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (yEnd > 4) { 52901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich yEnd = 4; 53001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 53101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int ymask = kYMask[yEnd]; 53201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 53301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 xEnd = width - x; 53401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (xEnd > 4) { 53501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich xEnd = 4; 53601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 53701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int mask = ymask & kXMask[xEnd]; 53801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 53901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte* q = block + (cy * 4) * 3; 54001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy); 54101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (pixelSize == 3) { 54201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich memcpy(q, p, xEnd * 3); 54301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 54401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 54501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich int pixel = (p[1] << 8) | p[0]; 54601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = convert5To8(pixel >> 11); 54701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = convert6To8(pixel >> 5); 54801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *q++ = convert5To8(pixel); 54901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich p += pixelSize; 55001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 55101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 55201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 55301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_encode_block(block, mask, encoded); 55401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich memcpy(pOut, encoded, sizeof(encoded)); 55501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut += sizeof(encoded); 55601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 55701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 55801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return 0; 55901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 56001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 56101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Decode an entire image. 56201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pIn - pointer to encoded data. 56301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pOut - pointer to the image data. Will be written such that the Red component of 56401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be 56501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// large enough to store entire image. 56601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 56701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 56801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichint etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut, 56901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 width, etc1_uint32 height, 57001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 pixelSize, etc1_uint32 stride) { 57101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (pixelSize < 2 || pixelSize > 3) { 57201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return -1; 57301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 57401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte block[ETC1_DECODED_BLOCK_SIZE]; 57501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 57601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 57701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 57801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 57901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 y = 0; y < encodedHeight; y += 4) { 58001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 yEnd = height - y; 58101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (yEnd > 4) { 58201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich yEnd = 4; 58301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 58401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 x = 0; x < encodedWidth; x += 4) { 58501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 xEnd = width - x; 58601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (xEnd > 4) { 58701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich xEnd = 4; 58801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 58901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_decode_block(pIn, block); 59001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pIn += ETC1_ENCODED_BLOCK_SIZE; 59101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 cy = 0; cy < yEnd; cy++) { 59201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich const etc1_byte* q = block + (cy * 4) * 3; 59301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte* p = pOut + pixelSize * x + stride * (y + cy); 59401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (pixelSize == 3) { 59501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich memcpy(p, q, xEnd * 3); 59601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } else { 59701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich for (etc1_uint32 cx = 0; cx < xEnd; cx++) { 59801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte r = *q++; 59901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte g = *q++; 60001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_byte b = *q++; 60101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); 60201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *p++ = (etc1_byte) pixel; 60301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich *p++ = (etc1_byte) (pixel >> 8); 60401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 60501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 60601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 60701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 60801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 60901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return 0; 61001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 61101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 61201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; 61301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 61401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6; 61501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8; 61601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10; 61701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12; 61801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14; 61901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 62001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0; 62101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 62201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) { 62301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[0] = (etc1_byte) (data >> 8); 62401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich pOut[1] = (etc1_byte) data; 62501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 62601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 62701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichstatic etc1_uint32 readBEUint16(const etc1_byte* pIn) { 62801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return (pIn[0] << 8) | pIn[1]; 62901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 63001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 63101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Format a PKM header 63201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 63301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichvoid etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) { 63401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich memcpy(pHeader, kMagic, sizeof(kMagic)); 63501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedWidth = (width + 3) & ~3; 63601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedHeight = (height + 3) & ~3; 63701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS); 63801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth); 63901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight); 64001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width); 64101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height); 64201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 64301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 64401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Check if a PKM header is correctly formatted. 64501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 64601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichetc1_bool etc1_pkm_is_valid(const etc1_byte* pHeader) { 64701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich if (memcmp(pHeader, kMagic, sizeof(kMagic))) { 64801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return false; 64901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich } 65001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET); 65101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET); 65201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET); 65301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 65401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 65501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return format == ETC1_RGB_NO_MIPMAPS && 65601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich encodedWidth >= width && encodedWidth - width < 4 && 65701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich encodedHeight >= height && encodedHeight - height < 4; 65801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 65901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 66001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Read the image width from a PKM header 66101cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 66201cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichetc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) { 66301cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET); 66401cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 66501cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 66601cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich// Read the image height from a PKM header 66701cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich 66801cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevichetc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){ 66901cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET); 67001cc538b290ecc9ccfdf1907fb714b76cf0f648bJack Palevich} 671