etc1.cpp 22 KB

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