etc1.cpp 21 KB

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