summaryrefslogtreecommitdiff
path: root/src/static_libs
diff options
context:
space:
mode:
authorMythri Venugopal <mythri.venugopal@samsung.com>2014-02-13 10:13:29 +0900
committerCedric BAIL <cedric.bail@free.fr>2014-04-01 22:00:13 +0900
commitebd318792392ea0bf6093794175b7f191199b6f0 (patch)
tree8f8960403082d4b7dca86eb0c41ff095d3e3ac5d /src/static_libs
parent2cac84f56794bfdff45002099f6c9d95376eff8a (diff)
rg_etc: convert code to C to fit in EFL tree.
Diffstat (limited to 'src/static_libs')
-rw-r--r--src/static_libs/rg_etc/rg_etc1.c2635
-rw-r--r--src/static_libs/rg_etc/rg_etc1.cpp2446
-rw-r--r--src/static_libs/rg_etc/rg_etc1.h73
3 files changed, 2666 insertions, 2488 deletions
diff --git a/src/static_libs/rg_etc/rg_etc1.c b/src/static_libs/rg_etc/rg_etc1.c
new file mode 100644
index 0000000..0550d40
--- /dev/null
+++ b/src/static_libs/rg_etc/rg_etc1.c
@@ -0,0 +1,2635 @@
1// File: rg_etc1.cpp - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
2// Please see ZLIB license at the end of rg_etc1.h.
3//
4// For more information Ericsson Texture Compression (ETC/ETC1), see:
5// http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
6//
7// v1.04 - 5/15/14 - Fix signed vs. unsigned subtraction problem (noticed when compiled with gcc) in pack_etc1_block_init().
8// This issue would cause an assert when this func. was called in debug. (Note this module was developed/testing with MSVC,
9// I still need to test it throughly when compiled with gcc.)
10//
11// v1.03 - 5/12/13 - Initial public release
12
13#include <stdlib.h>
14#include <memory.h>
15#include <assert.h>
16#include <math.h>
17
18#include "rg_etc1.h"
19
20#if defined(_DEBUG) || defined(DEBUG)
21#define RG_ETC1_BUILD_DEBUG
22#endif
23
24typedef unsigned long long uint64;
25typedef unsigned char uint8;
26typedef unsigned short uint16;
27typedef unsigned int uint;
28typedef unsigned int uint32;
29typedef unsigned char DATA8;
30
31#define false 0
32#define true 1
33#define RG_ETC1_ASSERT assert
34
35#define MIN(A, B) ((A < B) ? A : B)
36#define MAX(A, B) ((A > B) ? A : B)
37#define CLAMP(Value, Low, High) ((Value < Low) ? Low : ((Value > High) ? High : Value))
38#define SQUARE(Value) (Value * Value)
39
40#ifndef UINT_MAX
41#define UINT_MAX 4294967295U
42#endif
43
44#ifndef ULLONG_MAX
45#define ULLONG_MAX 18446744073709551615ULL
46#endif
47
48#define cUINT32_MAX UINT_MAX
49#define cUINT64_MAX ULLONG_MAX
50#define RG_ETC1_ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
51
52enum RG_Etc_Constants
53 {
54 cETC1BytesPerBlock = 8U,
55
56 cETC1SelectorBits = 2U,
57 cETC1SelectorValues = 1U << cETC1SelectorBits,
58 cETC1SelectorMask = cETC1SelectorValues - 1U,
59
60 cETC1BlockShift = 2U,
61 cETC1BlockSize = 1U << cETC1BlockShift,
62
63 cETC1LSBSelectorIndicesBitOffset = 0,
64 cETC1MSBSelectorIndicesBitOffset = 16,
65
66 cETC1FlipBitOffset = 32,
67 cETC1DiffBitOffset = 33,
68
69 cETC1IntenModifierNumBits = 3,
70 cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
71 cETC1RightIntenModifierTableBitOffset = 34,
72 cETC1LeftIntenModifierTableBitOffset = 37,
73
74 // Base+Delta encoding (5 bit bases, 3 bit delta)
75 cETC1BaseColorCompNumBits = 5,
76 cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
77
78 cETC1DeltaColorCompNumBits = 3,
79 cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
80 cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
81
82 cETC1BaseColor5RBitOffset = 59,
83 cETC1BaseColor5GBitOffset = 51,
84 cETC1BaseColor5BBitOffset = 43,
85
86 cETC1DeltaColor3RBitOffset = 56,
87 cETC1DeltaColor3GBitOffset = 48,
88 cETC1DeltaColor3BBitOffset = 40,
89
90 // Absolute (non-delta) encoding (two 4-bit per component bases)
91 cETC1AbsColorCompNumBits = 4,
92 cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
93
94 cETC1AbsColor4R1BitOffset = 60,
95 cETC1AbsColor4G1BitOffset = 52,
96 cETC1AbsColor4B1BitOffset = 44,
97
98 cETC1AbsColor4R2BitOffset = 56,
99 cETC1AbsColor4G2BitOffset = 48,
100 cETC1AbsColor4B2BitOffset = 40,
101
102 cETC1ColorDeltaMin = -4,
103 cETC1ColorDeltaMax = 3,
104
105 // Delta3:
106 // 0 1 2 3 4 5 6 7
107 // 000 001 010 011 100 101 110 111
108 // 0 1 2 3 -4 -3 -2 -1
109 };
110
111#ifndef WORDS_BIGENDIAN
112/* x86 */
113#define R_VAL(p) (((DATA8 *)(p))[0])
114#define G_VAL(p) (((DATA8 *)(p))[1])
115#define B_VAL(p) (((DATA8 *)(p))[2])
116#define A_VAL(p) (((DATA8 *)(p))[3])
117#define BA_VAL(p) ((DATA16 *)(p)[1])
118#define RG_VAL(p) ((DATA16 *)(p)[0])
119#else
120/* ppc */
121#define R_VAL(p) (((DATA8 *)(p))[3])
122#define G_VAL(p) (((DATA8 *)(p))[2])
123#define B_VAL(p) (((DATA8 *)(p))[1])
124#define A_VAL(p) (((DATA8 *)(p))[0])
125#define BA_VAL(p) ((DATA16 *)(p)[0])
126#define RG_VAL(p) ((DATA16 *)(p)[1])
127#endif
128
129//#define ARGB_JOIN(a,r,g,b) \
130// (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
131
132#define ARGB_JOIN(a,r,g,b) \
133 (((a) << 24) + ((b) << 16) + ((g) << 8) + (r))
134static unsigned char rg_etc_quant5_tab[256 + 16];
135
136static const int rg_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] = {
137 { -8, -2, 2, 8 },
138 { -17, -5, 5, 17 },
139 { -29, -9, 9, 29 },
140 { -42, -13, 13, 42 },
141 { -60, -18, 18, 60 },
142 { -80, -24, 24, 80 },
143 { -106, -33, 33, 106 },
144 { -183, -47, 47, 183 }
145};
146
147static const unsigned char rg_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
148static const unsigned char rg_etc_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
149
150// Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte.
151static unsigned short rg_etc1_inverse_lookup[2*8*4][256]; // [diff/inten_table/selector][desired_color]
152
153// rg_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color.
154// To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8)
155static const unsigned short rg_etc_color8_to_etc_block_config_0_255[2][33] = {
156 {
157 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008,
158 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E, 0x0001, 0x0011,
159 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B,
160 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF
161 },
162 {
163 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38,
164 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E, 0x1E31, 0x1F21,
165 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B,
166 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF
167 },
168};
169
170// Really only [254][11].
171static const unsigned short rg_etc_color8_to_etc_block_config_1_to_254[254][12] = {
172 { 0x021C, 0x0D0D, 0xFFFF },
173 { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF },
174 { 0x0113, 0x0217, 0xFFFF },
175 { 0x0116, 0x031E, 0x0B0E, 0x0405, 0xFFFF },
176 { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF },
177 { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF },
178 { 0x0303, 0x0215, 0x0607, 0xFFFF },
179 { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF },
180 { 0x0100, 0x0024, 0x0306, 0x0025, 0x041B, 0x0E0D, 0xFFFF },
181 { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF },
182 { 0x0213, 0x0317, 0xFFFF },
183 { 0x0112, 0x0505, 0xFFFF },
184 { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF },
185 { 0x0211, 0x0909, 0xFFFF },
186 { 0x0110, 0x0315, 0x0707, 0x0419, 0x180F, 0xFFFF },
187 { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF },
188 { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B, 0x0F0D, 0xFFFF },
189 { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF },
190 { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF },
191 { 0x0605, 0x0417, 0xFFFF },
192 { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF },
193 { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF },
194 { 0x0519, 0x190F, 0xFFFF },
195 { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF },
196 { 0x0130, 0x0214, 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF },
197 { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF },
198 { 0x031A, 0x0D0B, 0x091F, 0xFFFF },
199 { 0x0413, 0x0705, 0x0517, 0xFFFF },
200 { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF },
201 { 0x0126, 0x080C, 0x0B09, 0xFFFF },
202 { 0x0411, 0x0619, 0x1A0F, 0xFFFF },
203 { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B, 0xFFFF },
204 { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF },
205 { 0x0132, 0x0302, 0x0229, 0x110D, 0xFFFF },
206 { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF },
207 { 0x0220, 0x0513, 0x0617, 0xFFFF },
208 { 0x0135, 0x0805, 0x0327, 0xFFFF },
209 { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF },
210 { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F, 0xFFFF },
211 { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF },
212 { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF },
213 { 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF },
214 { 0x0300, 0x0224, 0x0506, 0x0521, 0x0F0B, 0x0B1F, 0xFFFF },
215 { 0x041A, 0x0613, 0x0717, 0xFFFF },
216 { 0x0235, 0x0905, 0xFFFF },
217 { 0x0312, 0x0134, 0x0523, 0x0427, 0xFFFF },
218 { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF },
219 { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F, 0xFFFF },
220 { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF },
221 { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B, 0x130D, 0xFFFF },
222 { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF },
223 { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF },
224 { 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF },
225 { 0x0623, 0x0527, 0xFFFF },
226 { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F, 0xFFFF },
227 { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF },
228 { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D, 0xFFFF },
229 { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF },
230 { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529, 0x140D, 0xFFFF },
231 { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF },
232 { 0x051A, 0x0813, 0x0B05, 0x0917, 0xFFFF },
233 { 0x0723, 0x0435, 0x0627, 0xFFFF },
234 { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF },
235 { 0x0326, 0x0A0C, 0x012E, 0x0811, 0x0A19, 0x1E0F, 0xFFFF },
236 { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF },
237 { 0x0410, 0x0901, 0x0633, 0x0725, 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF },
238 { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF },
239 { 0x0332, 0x0502, 0x0821, 0x0139, 0x120B, 0x0E1F, 0xFFFF },
240 { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF },
241 { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF },
242 { 0x0823, 0x032F, 0xFFFF },
243 { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF },
244 { 0x0422, 0x0604, 0x090A, 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF },
245 { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF },
246 { 0x032A, 0x0825, 0x0437, 0x0729, 0x0C1B, 0x160D, 0xFFFF },
247 { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF },
248 { 0x0500, 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF },
249 { 0x061A, 0x0635, 0x0D05, 0xFFFF },
250 { 0x0923, 0x0827, 0xFFFF },
251 { 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF },
252 { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19, 0x072B, 0xFFFF },
253 { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF },
254 { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D, 0xFFFF },
255 { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF },
256 { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF },
257 { 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF },
258 { 0x0520, 0x0A23, 0x0927, 0xFFFF },
259 { 0x0B11, 0x1209, 0x013B, 0x052F, 0xFFFF },
260 { 0x0616, 0x081E, 0x0D19, 0xFFFF },
261 { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D, 0x0F1D, 0xFFFF },
262 { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF },
263 { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF },
264 { 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF },
265 { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05, 0x0D17, 0xFFFF },
266 { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF },
267 { 0x1309, 0x023B, 0x062F, 0xFFFF },
268 { 0x0612, 0x0434, 0x013A, 0x0C11, 0x0E19, 0xFFFF },
269 { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF },
270 { 0x0D01, 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF },
271 { 0x0610, 0x0A29, 0x190D, 0xFFFF },
272 { 0x0718, 0x042C, 0x0C21, 0x0539, 0x160B, 0x121F, 0xFFFF },
273 { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF },
274 { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27, 0xFFFF },
275 { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF },
276 { 0x0D11, 0x0F19, 0x1409, 0xFFFF },
277 { 0x0716, 0x003C, 0x091E, 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF },
278 { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D, 0xFFFF },
279 { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF },
280 { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF },
281 { 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF },
282 { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF },
283 { 0x081A, 0x0D23, 0x0C27, 0xFFFF },
284 { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF },
285 { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307, 0x1019, 0x0B2B, 0x013D, 0xFFFF },
286 { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF },
287 { 0x0C33, 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF },
288 { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF },
289 { 0x0818, 0x052C, 0x0F13, 0x180B, 0x141F, 0xFFFF },
290 { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF },
291 { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF },
292 { 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF },
293 { 0x1119, 0x023D, 0xFFFF },
294 { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103, 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF },
295 { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B, 0xFFFF },
296 { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF },
297 { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF },
298 { 0x0730, 0x0814, 0x0536, 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF },
299 { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF },
300 { 0x091A, 0x1709, 0x063B, 0x0A2F, 0xFFFF },
301 { 0x1011, 0x1219, 0x033D, 0xFFFF },
302 { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115, 0x1507, 0x0D2B, 0xFFFF },
303 { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF },
304 { 0x0E29, 0x1D0D, 0xFFFF },
305 { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF },
306 { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF },
307 { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF },
308 { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF },
309 { 0x0820, 0x1111, 0x1319, 0x1809, 0xFFFF },
310 { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF },
311 { 0x0916, 0x023C, 0x0B1E, 0x1031, 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF },
312 { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF },
313 { 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF },
314 { 0x072A, 0x1213, 0x1317, 0xFFFF },
315 { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35, 0x1505, 0xFFFF },
316 { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF },
317 { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F, 0xFFFF },
318 { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF },
319 { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D, 0x161D, 0xFFFF },
320 { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF },
321 { 0x1221, 0x0B39, 0x1029, 0xFFFF },
322 { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF },
323 { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF },
324 { 0x0832, 0x0A02, 0x1223, 0x1127, 0xFFFF },
325 { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF },
326 { 0x0920, 0x1519, 0x063D, 0xFFFF },
327 { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF },
328 { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133, 0x1225, 0x0E37, 0x161B, 0xFFFF },
329 { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF },
330 { 0x0C39, 0x1D0B, 0x191F, 0xFFFF },
331 { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF },
332 { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF },
333 { 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF },
334 { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF },
335 { 0x1331, 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF },
336 { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D, 0x181D, 0xFFFF },
337 { 0x0926, 0x072E, 0x1229, 0xFFFF },
338 { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF },
339 { 0x0A10, 0x1513, 0x1617, 0xFFFF },
340 { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF },
341 { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF },
342 { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF },
343 { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF },
344 { 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF },
345 { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF },
346 { 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF },
347 { 0x1613, 0x1717, 0xFFFF },
348 { 0x092A, 0x1235, 0x1905, 0xFFFF },
349 { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF },
350 { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09, 0x0C3B, 0x102F, 0xFFFF },
351 { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF },
352 { 0x1531, 0x1701, 0x1803, 0x122D, 0x1A1D, 0xFFFF },
353 { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF },
354 { 0x0A26, 0x003E, 0x082E, 0x1621, 0x0F39, 0x1429, 0x003F, 0xFFFF },
355 { 0x1713, 0x1C1F, 0xFFFF },
356 { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF },
357 { 0x0C18, 0x092C, 0x1623, 0x1527, 0xFFFF },
358 { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF },
359 { 0x0A28, 0x0D1C, 0x1919, 0x0A3D, 0xFFFF },
360 { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF },
361 { 0x1801, 0x1533, 0x1625, 0x1237, 0x1A1B, 0xFFFF },
362 { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF },
363 { 0x0B22, 0x0D04, 0x1039, 0x1D1F, 0xFFFF },
364 { 0x1813, 0x1B05, 0x1917, 0xFFFF },
365 { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF },
366 { 0x0B30, 0x0C14, 0x0936, 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF },
367 { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF },
368 { 0x0D1A, 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF },
369 { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF },
370 { 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF },
371 { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF },
372 { 0x1913, 0x1A17, 0xFFFF },
373 { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF },
374 { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF },
375 { 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF },
376 { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF },
377 { 0x0C20, 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF },
378 { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF },
379 { 0x0D16, 0x063C, 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF },
380 { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF },
381 { 0x1635, 0x1D05, 0xFFFF },
382 { 0x0B2A, 0x1923, 0x1827, 0xFFFF },
383 { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF },
384 { 0x0D00, 0x0C24, 0x0F06, 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF },
385 { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF },
386 { 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF },
387 { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF },
388 { 0x0C26, 0x023E, 0x0A2E, 0x1B13, 0xFFFF },
389 { 0x1735, 0x1E05, 0x1C17, 0xFFFF },
390 { 0x0D10, 0x1A23, 0x1927, 0xFFFF },
391 { 0x0E18, 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF },
392 { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF },
393 { 0x0C28, 0x0F1C, 0x1A31, 0x1D03, 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF },
394 { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF },
395 { 0x1B21, 0x1929, 0x053F, 0xFFFF },
396 { 0x0E16, 0x073C, 0x1439, 0xFFFF },
397 { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF },
398 { 0x1B23, 0x1835, 0x1A27, 0xFFFF },
399 { 0x0C2A, 0x123B, 0x162F, 0xFFFF },
400 { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF },
401 { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF },
402 { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B, 0x182D, 0xFFFF },
403 { 0x1A29, 0x063F, 0xFFFF },
404 { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF },
405 { 0x0D26, 0x033E, 0x0B2E, 0x1D13, 0x1E17, 0xFFFF },
406 { 0x1935, 0x1B27, 0xFFFF },
407 { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF },
408 { 0x0F18, 0x0C2C, 0x1D11, 0x1F19, 0xFFFF },
409 { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF },
410 { 0x0D28, 0x1C31, 0x1E01, 0x1B33, 0x192D, 0xFFFF },
411 { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF },
412 { 0x1D21, 0x1639, 0xFFFF },
413 { 0x0F16, 0x083C, 0x1E13, 0x1F17, 0xFFFF },
414 { 0x0E22, 0x1A35, 0xFFFF },
415 { 0x1D23, 0x1C27, 0xFFFF },
416 { 0x0D2A, 0x1E11, 0x143B, 0x182F, 0xFFFF },
417 { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF },
418 { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01, 0x1A2D, 0xFFFF },
419 { 0x1C33, 0x1D25, 0x1937, 0xFFFF },
420 { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF },
421 { 0x0F12, 0x0D34, 0x0A3A, 0x1F13, 0xFFFF },
422 { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF },
423 { 0x1E23, 0x1D27, 0xFFFF },
424 { 0x0F10, 0x1F11, 0x153B, 0x192F, 0xFFFF },
425 { 0x0D2C, 0x123D, 0xFFFF },
426};
427
428typedef union
429{
430 struct comp {
431 unsigned char r;
432 unsigned char g;
433 unsigned char b;
434 unsigned char a;
435 } comp;
436
437 unsigned char c[4];
438
439 unsigned int m_u32;
440} color_quad_u8;
441
442static inline int
443rg_etc1_color_quad_u8_clamp(int v)
444{
445 if (v & 0xFFFFFF00U)
446 v = ((~v) >> 31) & 0xFF;
447 return v;
448}
449
450static inline void
451rg_etc1_color_quad_u8_init(color_quad_u8 *color, int r, int g, int b, int alpha)
452{
453 color->comp.r = rg_etc1_color_quad_u8_clamp(r);
454 color->comp.g = rg_etc1_color_quad_u8_clamp(g);
455 color->comp.b = rg_etc1_color_quad_u8_clamp(b);
456 color->comp.a = rg_etc1_color_quad_u8_clamp(alpha);
457}
458static inline void
459rg_etc1_color_quad_u8_copy(color_quad_u8 *dst, const color_quad_u8 *src)
460{
461 dst->m_u32 = src->m_u32;
462}
463
464static inline void
465rg_etc1_color_quad_u8_clear(color_quad_u8 *color)
466{
467 color->m_u32 = 0;
468}
469
470static inline unsigned int
471rg_etc1_color_quad_u8_rgb_squared_distance(color_quad_u8 color1, color_quad_u8 color2)
472{
473
474 return SQUARE((color1.comp.r - color2.comp.r)) + SQUARE((color1.comp.g - color2.comp.g)) + SQUARE((color1.comp.b - color2.comp.b));
475}
476
477static inline void
478rg_etc1_color_quad_u8_component_set(color_quad_u8 *color, unsigned char idx, unsigned char value)
479{
480
481 switch (idx)
482 {
483 case 0: color->comp.r = value; break;
484 case 1: color->comp.g = value; break;
485 case 2: color->comp.b = value; break;
486 case 3: color->comp.a = value; break;
487 default: abort();
488 }
489
490}
491
492static inline unsigned int
493rg_etc1_color_quad_duplicate_init(unsigned char y, unsigned char alpha)
494{
495 return ARGB_JOIN(alpha, y, y, y);
496}
497
498static inline unsigned int
499rg_etc1_color_quad_init(unsigned char r, unsigned char g, unsigned char b, unsigned char alpha)
500{
501 return ARGB_JOIN(alpha, r, g, b);
502}
503
504static inline unsigned int
505rg_etc1_color_quad_set(unsigned int old_color, unsigned int new_color, unsigned char preserve_alpha)
506{
507 if (preserve_alpha)
508 {
509 unsigned char r, g, b, a;
510
511 a = A_VAL(&old_color);
512 r = R_VAL(&new_color);
513 g = G_VAL(&new_color);
514 b = B_VAL(&new_color);
515
516 return ARGB_JOIN(a, r, g, b);
517 }
518 return new_color;
519}
520
521static inline void
522rg_etc1_color_quad_get(unsigned int color, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *alpha)
523{
524 if (r) *r = R_VAL(&color);
525 if (g) *g = G_VAL(&color);
526 if (b) *b = B_VAL(&color);
527 if (alpha) *alpha = A_VAL(&color);
528}
529
530static inline unsigned char
531rg_etc1_color_quad_component_get(unsigned int color, unsigned char idx)
532{
533 switch (idx)
534 {
535 case 0: return R_VAL(&color);
536 case 1: return G_VAL(&color);
537 case 2: return B_VAL(&color);
538 case 3: return A_VAL(&color);
539 default: abort();
540 }
541 return 0;
542}
543
544static inline unsigned int
545rg_etc1_color_quad_component_set(unsigned int color, unsigned char idx, unsigned char value)
546{
547 unsigned char r, g, b, a;
548
549 rg_etc1_color_quad_get(color, &r, &g, &b, &a);
550
551 switch (idx)
552 {
553 case 0: r = value; break;
554 case 1: g = value; break;
555 case 2: b = value; break;
556 case 3: a = value; break;
557 default: abort();
558 }
559
560 return rg_etc1_color_quad_init(r, g, b, a);
561}
562
563static inline unsigned int
564rg_etc1_color_quad_grayscale_set(unsigned int color, unsigned char l)
565{
566 unsigned char a;
567
568 a = A_VAL(&color);
569
570 return rg_etc1_color_quad_init(l, l, l, a);
571}
572
573static inline unsigned int
574rg_etc1_color_quad_clamp(unsigned int color, unsigned int low, unsigned high)
575{
576 unsigned char *c = (unsigned char *)&color;
577 unsigned char *l = (unsigned char *)&low;
578 unsigned char *h = (unsigned char *)&high;
579 unsigned int i;
580
581 for (i = 0; i < 4; i++)
582 c[i] = clamp(c[i], l[i], h[i]);
583
584 return color;
585}
586
587static inline unsigned int
588rg_etc1_color_quad_component_clamp(unsigned int color, unsigned int low, unsigned high)
589{
590 unsigned char *c = (unsigned char *)&color;
591 unsigned int i;
592
593 for (i = 0; i < 4; i++)
594 c[i] = clamp(c[i], low, high);
595
596 return color;
597}
598
599// Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
600static inline unsigned char
601rg_etc1_color_quad_luma601_get(unsigned int color)
602{
603 unsigned char r, g, b;
604 rg_etc1_color_quad_get(color, &r, &g, &b, NULL);
605 return ((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
606}
607
608// Returns REC 709 luma.
609static inline unsigned char
610rg_etc1_color_quad_luma709_get(unsigned int color)
611{
612 unsigned char r, g, b;
613 rg_etc1_color_quad_get(color, &r, &g, &b, NULL);
614 return ((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
615}
616
617static inline unsigned int
618rg_etc1_color_quad_rgb_squared_distance(unsigned int color1, unsigned int color2)
619{
620 unsigned char r1, g1, b1;
621 unsigned char r2, g2, b2;
622
623 rg_etc1_color_quad_get(color1, &r1, &g1, &b1, NULL);
624 rg_etc1_color_quad_get(color2, &r2, &g2, &b2, NULL);
625
626 return SQUARE(r1 - r2) + SQUARE(g1 - g2) + SQUARE(b1 - b2);
627}
628
629static inline unsigned int
630rg_etc1_color_quad_argb_squared_distance(unsigned int color1, unsigned int color2)
631{
632 unsigned char r1, g1, b1, a1;
633 unsigned char r2, g2, b2, a2;
634
635 rg_etc1_color_quad_get(color1, &r1, &g1, &b1, &a1);
636 rg_etc1_color_quad_get(color2, &r2, &g2, &b2, &a2);
637
638 return SQUARE(r1 - r2) + SQUARE(g1 - g2) + SQUARE(b1 - b2) + SQUARE(a1 - a1);
639}
640
641static inline unsigned char
642rg_etc1_color_quad_rgb_equals(unsigned int color1, unsigned int color2)
643{
644 A_VAL(&color1) = 0;
645 A_VAL(&color2) = 0;
646
647 return color1 == color2;
648}
649
650static inline unsigned int
651rg_etc1_color_quad_add(unsigned int color1, unsigned int color2)
652{
653 unsigned char *c1 = (unsigned char *)&color1;
654 unsigned char *c2 = (unsigned char *)&color2;
655 unsigned int i;
656
657 for (i = 0; i < 4; i++)
658 {
659 unsigned short t;
660
661 t = c1[i] + c2[i];
662 c1[i] = (unsigned char) (CLAMP(t, 0, 255));
663 }
664
665 return color1;
666}
667
668static inline unsigned int
669rg_etc1_color_quad_del(unsigned int color1, unsigned int color2)
670{
671 unsigned char *c1 = (unsigned char *)&color1;
672 unsigned char *c2 = (unsigned char *)&color2;
673 unsigned int i;
674
675 for (i = 0; i < 4; i++)
676 {
677 short t;
678
679 t = c1[i] - c2[i];
680 c1[i] = (unsigned char) (CLAMP(t, 0, 255));
681 }
682
683 return color1;
684}
685
686static inline void
687rg_etc1_vec_init(float v[3], float s)
688{
689 v[0] = s; v[1] = s; v[2] = s;
690}
691
692static inline void
693rg_etc1_vec_set(float v[3], float x, float y, float z)
694{
695 v[0] = x; v[1] = y; v[2] = z;
696}
697
698static inline void
699rg_etc1_vec_copy(float dst[3], float src[3])
700{
701 dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
702}
703
704static inline void
705rg_etc1_vec_add(float r[3], float a[3])
706{
707 unsigned int i;
708
709 //for (i = 0; i < RG_ETC1_ARRAY_SIZE(r); i++)
710 for (i = 0; i < 3; i++)
711 r[i] += a[i];
712}
713
714static inline void
715rg_etc1_vec_scale(float r[3], float s)
716{
717 unsigned int i;
718
719 //for (i = 0; i < RG_ETC1_ARRAY_SIZE(r); i++)
720 for (i = 0; i < 3; i++)
721 r[i] *= s;
722}
723
724static inline unsigned char
725rg_etc1_block_byte_bits_get(const unsigned char bytes[8], unsigned char offset, unsigned char num)
726{
727 const unsigned char byte_offset = 7 - (offset >> 3);
728 const unsigned char byte_bit_offset = offset & 7;
729
730 return (bytes[byte_offset] >> byte_bit_offset) & ((1 << num) - 1);
731}
732
733static inline void
734rg_etc1_block_byte_bits_set(unsigned char bytes[8], unsigned char offset, unsigned char num, unsigned char bits)
735{
736 const unsigned char byte_offset = 7 - (offset >> 3);
737 const unsigned char byte_bit_offset = offset & 7;
738 const unsigned char mask = (1 << num) - 1;
739 bytes[byte_offset] &= ~(mask << byte_bit_offset);
740 bytes[byte_offset] |= (((!!bits) & 0x1) << byte_bit_offset);
741}
742
743static inline unsigned char
744rg_etc1_block_flip_bit_get(const unsigned char bytes[8])
745{
746 return (bytes[3] & 1) != 0;
747}
748
749static inline void
750rg_etc1_block_flip_bit_set(unsigned char bytes[8], unsigned char flip)
751{
752 bytes[3] &= ~1;
753 bytes[3] |= (!!flip) & 0x1;
754}
755
756static inline unsigned char
757rg_etc1_block_diff_bit_get(const unsigned char bytes[8])
758{
759 return (bytes[3] & 2) != 0;
760}
761
762static inline void
763rg_etc1_block_diff_bit_set(unsigned char bytes[8], unsigned char diff)
764{
765 bytes[3] &= ~2;
766 bytes[3] |= ((!!diff) & 0x1) << 1;
767}
768
769static inline void
770rg_etc1_block_clear(unsigned char bytes[8])
771{
772 memset(bytes, 0, sizeof (bytes));
773}
774
775// Returns intensity modifier table (0-7) used by subblock subblock_id.
776// subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
777static inline unsigned char
778rg_etc1_block_inten_table_get(const unsigned char bytes[8], unsigned char subblock_id)
779{
780 const unsigned char offset = subblock_id ? 2 : 5;
781 assert(subblock_id < 2);
782 return (bytes[3] >> offset) & 7;
783}
784
785// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
786static inline void
787rg_etc1_block_inten_table_set(unsigned char bytes[8], unsigned char subblock_id, unsigned char t)
788{
789 const unsigned char offset = subblock_id ? 2 : 5;
790 assert(subblock_id < 2);
791 assert(t < 8);
792 bytes[3] &= ~(7 << offset);
793 bytes[3] |= (t << offset);
794}
795
796// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
797static inline unsigned char
798rg_etc1_block_selector_get(const unsigned char bytes[8], unsigned char x, unsigned char y)
799{
800 assert((x | y) < 4);
801
802 const unsigned char bit_index = x * 4 + y;
803 const unsigned char byte_bit_offset = bit_index & 7;
804 const unsigned char *p = &bytes[7 - (bit_index >> 3)];
805 const unsigned char lsb = (p[0] >> byte_bit_offset) & 1;
806 const unsigned char msb = (p[-2] >> byte_bit_offset) & 1;
807 const unsigned char val = lsb | (msb << 1);
808
809 return rg_etc1_to_selector_index[val];
810}
811
812// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
813static inline void
814rg_etc1_block_selector_set(unsigned char bytes[8], unsigned char x, unsigned char y, unsigned char val)
815{
816 assert((x | y) < 4);
817
818 const unsigned char bit_index = x * 4 + y;
819
820 unsigned char *p = &bytes[7 - (bit_index >> 3)];
821
822 const unsigned char byte_bit_offsets = bit_index & 7;
823 const unsigned char mask = 1 << byte_bit_offsets;
824 const unsigned char etc1_val = rg_etc_selector_index_to_etc1[val];
825
826 const unsigned char lsb = etc1_val & 1;
827 const unsigned char msb = etc1_val >> 1;
828
829 p[0] &= ~mask;
830 p[0] |= (lsb << byte_bit_offsets);
831
832 p[-2] &= ~mask;
833 p[-2] |= (msb << byte_bit_offsets);
834}
835
836static inline unsigned short
837rg_etc_block_base4_color_get(const unsigned char bytes[8], unsigned char idx)
838{
839 unsigned short r, g, b;
840
841 if (idx)
842 {
843 r = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4R2BitOffset, 4);
844 g = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4G2BitOffset, 4);
845 b = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4B2BitOffset, 4);
846 }
847 else
848 {
849 r = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4R1BitOffset, 4);
850 g = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4G1BitOffset, 4);
851 b = rg_etc1_block_byte_bits_get(bytes, cETC1AbsColor4B1BitOffset, 4);
852 }
853
854 return b | (g << 4) | (r << 8);
855}
856
857static inline void
858rg_etc1_block_base4_color_set(unsigned char bytes[8], unsigned char idx, unsigned short c)
859{
860 if (idx)
861 {
862 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
863 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
864 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4B2BitOffset, 4, c & 15);
865 }
866 else
867 {
868 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
869 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
870 rg_etc1_block_byte_bits_set(bytes, cETC1AbsColor4B1BitOffset, 4, c & 15);
871 }
872}
873
874static inline unsigned short
875rg_etc1_block_base5_color_get(const unsigned char bytes[8])
876{
877 unsigned short r, g, b;
878
879 r = rg_etc1_block_byte_bits_get(bytes, cETC1BaseColor5RBitOffset, 5);
880 g = rg_etc1_block_byte_bits_get(bytes, cETC1BaseColor5GBitOffset, 5);
881 b = rg_etc1_block_byte_bits_get(bytes, cETC1BaseColor5BBitOffset, 5);
882
883 return b | (g << 5) | (r << 10);
884}
885
886static inline void
887rg_etc1_block_base5_color_set(unsigned char bytes[8], unsigned short c)
888{
889 rg_etc1_block_byte_bits_set(bytes, cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
890 rg_etc1_block_byte_bits_set(bytes, cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
891 rg_etc1_block_byte_bits_set(bytes, cETC1BaseColor5BBitOffset, 5, c & 31);
892}
893
894static inline unsigned short
895rg_etc1_block_delta3_color_get(const unsigned char bytes[8])
896{
897 unsigned short r, g, b;
898
899 r = rg_etc1_block_byte_bits_get(bytes, cETC1DeltaColor3RBitOffset, 3);
900 g = rg_etc1_block_byte_bits_get(bytes, cETC1DeltaColor3GBitOffset, 3);
901 b = rg_etc1_block_byte_bits_get(bytes, cETC1DeltaColor3BBitOffset, 3);
902
903 return b | (g << 3) | (r << 6);
904}
905
906static inline void
907rg_etc1_block_delta3_color_set(unsigned char bytes[8], unsigned short c)
908{
909 rg_etc1_block_byte_bits_set(bytes, cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
910 rg_etc1_block_byte_bits_set(bytes, cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
911 rg_etc1_block_byte_bits_set(bytes, cETC1DeltaColor3BBitOffset, 3, c & 7);
912}
913
914static inline unsigned short
915rg_etc1_block_color5_component_pack(unsigned char r, unsigned char g, unsigned char b,
916 unsigned char scaled, unsigned char bias)
917{
918 if (scaled)
919 {
920 r = (r * 31 + bias) / 255U;
921 g = (g * 31 + bias) / 255U;
922 b = (b * 31 + bias) / 255U;
923 }
924
925 r = MIN(r, 31);
926 g = MIN(g, 31);
927 b = MIN(b, 31);
928
929 return b | (g << 5) | (r << 10);
930}
931
932static inline unsigned short
933rg_etc1_block_color5_pack(unsigned int c, unsigned char scaled, unsigned char bias)
934{
935 unsigned char r, g, b;
936
937 rg_etc1_color_quad_get(c, &r, &g, &b, NULL);
938 return rg_etc1_block_color5_component_pack(r, g, b, scaled, bias);
939}
940
941static inline void
942rg_etc1_block_color5_component_unpack(unsigned char *r, unsigned char *g, unsigned char *b,
943 unsigned short packed_color5, unsigned scaled)
944{
945 *r = (packed_color5 >> 10) & 31;
946 *g = (packed_color5 >> 5) & 31;
947 *b = packed_color5 & 31;
948
949 if (scaled)
950 {
951 *b = (*b << 3) | (*b >> 2);
952 *g = (*g << 3) | (*g >> 2);
953 *r = (*r << 3) | (*r >> 2);
954 }
955}
956
957static inline unsigned int
958rg_etc1_block_color5_unpack(unsigned short packed_color5, unsigned char scaled, unsigned char alpha)
959{
960 unsigned char r, g, b;
961
962 rg_etc1_block_color5_component_unpack(&r, &g, &b, packed_color5, scaled);
963
964 return rg_etc1_color_quad_init(r, g, b, MIN(alpha, 255));
965}
966
967// Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
968static inline unsigned int
969rg_etc1_block_delta3_pack(char r, char g, char b)
970{
971 assert((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
972 assert((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
973 assert((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
974
975 if (r < 0) r += 8;
976 if (g < 0) g += 8;
977 if (b < 0) b += 8;
978
979 return b | (g << 3) | (r << 6);
980}
981
982// Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
983static inline void
984rg_etc1_block_delta3_unpack(char *r, char *g, char *b, unsigned short packed_delta3)
985{
986 *r = (packed_delta3 >> 6) & 7;
987 *g = (packed_delta3 >> 3) & 7;
988 *b = packed_delta3 & 7;
989
990 if (*r >= 4) *r -= 8;
991 if (*g >= 4) *g -= 8;
992 if (*b >= 4) *b -= 8;
993}
994
995static inline unsigned short
996rg_etc1_block_color4_component_pack(unsigned char r, unsigned char g, unsigned char b,
997 unsigned char scaled, unsigned char bias)
998{
999 if (scaled)
1000 {
1001 r = (r * 15 + bias) / 255;
1002 g = (g * 15 + bias) / 255;
1003 b = (b * 15 + bias) / 255;
1004 }
1005
1006 r = MIN(r, 15);
1007 g = MIN(g, 15);
1008 b = MIN(b, 15);
1009
1010 return b | (g << 4) | (r << 8);
1011}
1012
1013static inline unsigned short
1014rg_etc1_block_color4_pack(unsigned int color, unsigned char scaled, unsigned char bias)
1015{
1016 unsigned char r, g, b;
1017
1018 rg_etc1_color_quad_get(color, &r, &g, &b, NULL);
1019 return rg_etc1_block_color4_component_pack(r, g, b, scaled, bias);
1020}
1021
1022static inline void
1023rg_etc1_block_color4_component_unpack(unsigned char *r, unsigned char *g, unsigned char *b,
1024 unsigned short packed_color4, bool scaled)
1025{
1026 *r = (packed_color4 >> 8) & 15;
1027 *g = (packed_color4 >> 4) & 15;
1028 *b = packed_color4 & 15;
1029
1030 if (scaled)
1031 {
1032 *b = (*b << 4) | *b;
1033 *g = (*g << 4) | *g;
1034 *r = (*r << 4) | *r;
1035 }
1036}
1037
1038static inline unsigned int
1039rg_etc1_block_color4_unpack(unsigned short packed_color4, unsigned char scaled, unsigned char alpha)
1040{
1041 unsigned char r, g, b;
1042
1043 rg_etc1_block_color4_component_unpack(&r, &g, &b, packed_color4, scaled);
1044
1045 return rg_etc1_color_quad_init(r, g, b, 255);
1046}
1047
1048
1049static inline unsigned char
1050rg_etc1_block_color5_delta3_component_unpack(unsigned char *r, unsigned char *g, unsigned char *b,
1051 unsigned short packed_color5, unsigned short packed_delta3, bool scaled)
1052{
1053 unsigned char success = 1;
1054 char dc_r, dc_g, dc_b;
1055
1056 rg_etc1_block_delta3_unpack(&dc_r, &dc_g, &dc_b, packed_delta3);
1057
1058 *r = ((packed_color5 >> 10) & 31) + dc_r;
1059 *g = ((packed_color5 >> 5) & 31) + dc_g;
1060 *b = (packed_color5 & 31) + dc_b;
1061
1062 if ((*r | *g | *b) > 31)
1063 {
1064 success = 0;
1065 *r = CLAMP(*r, 0, 31);
1066 *g = CLAMP(*g, 0, 31);
1067 *b = CLAMP(*b, 0, 31);
1068 }
1069
1070 if (scaled)
1071 {
1072 *r = (*r << 3) | (*r >> 2);
1073 *g = (*g << 3) | (*g >> 2);
1074 *b = (*b << 3) | (*b >> 2);
1075 }
1076
1077 return success;
1078}
1079
1080
1081static inline unsigned char
1082rg_etc1_block_color5_delta3_unpack(unsigned int *result,
1083 unsigned short packed_color5, unsigned short packed_delta3,
1084 bool scaled, unsigned char alpha)
1085{
1086 unsigned char success;
1087 unsigned char r, g, b;
1088
1089 success = rg_etc1_block_color5_delta3_component_unpack(&r, &g, &b, packed_color5, packed_delta3, scaled);
1090
1091 *result = rg_etc1_color_quad_init(r, g, b, alpha);
1092 return success;
1093}
1094
1095static inline void
1096rg_etc1_block_sublock_diff(unsigned int dst[4], const int *pInten_modifer_table,
1097 unsigned char r, unsigned char g, unsigned char b)
1098{
1099 int i;
1100
1101 for (i = 0; i < 4; i++)
1102 {
1103 int y = pInten_modifer_table[i];
1104
1105 dst[i] = rg_etc1_color_quad_init(CLAMP((int)r + y, 0, 255),
1106 CLAMP((int) g + y,0, 255),
1107 CLAMP((int) b + y,0, 255),
1108 255);
1109 }
1110}
1111
1112static inline void
1113rg_etc1_block_subblock_color5_diff_get(unsigned int dst[4], unsigned short packed_color5, unsigned char table_idx)
1114{
1115 const int *pInten_modifer_table;
1116 unsigned char r, g, b;
1117
1118 assert(table_idx < cETC1IntenModifierValues);
1119
1120 rg_etc1_block_color5_component_unpack(&r, &g, &b, packed_color5, 1);
1121
1122 pInten_modifer_table = &rg_etc1_inten_tables[table_idx][0];
1123 rg_etc1_block_sublock_diff(dst, pInten_modifer_table, r, g, b);
1124}
1125
1126static inline unsigned char
1127rg_etc1_block_subblock_color5_delta3_diff_get(unsigned int dst[4],
1128 unsigned short packed_color5, unsigned short packed_delta3,
1129 unsigned char table_idx)
1130{
1131 const int *pInten_modifer_table;
1132 unsigned char r, g, b;
1133 unsigned char success;
1134
1135 assert(table_idx < cETC1IntenModifierValues);
1136
1137 success = rg_etc1_block_color5_delta3_component_unpack(&r, &g, &b, packed_color5, packed_delta3, 1);
1138
1139 pInten_modifer_table = &rg_etc1_inten_tables[table_idx][0];
1140 rg_etc1_block_sublock_diff(dst, pInten_modifer_table, r, g, b);
1141
1142 return success;
1143}
1144
1145static inline void
1146rg_etc1_block_subblock_color4_abs_get(unsigned int dst[4], unsigned short packed_color4, unsigned char table_idx)
1147{
1148 const int *pInten_modifer_table;
1149 unsigned char r, g, b;
1150
1151 assert(table_idx < cETC1IntenModifierValues);
1152
1153 rg_etc1_block_color4_component_unpack(&r, &g, &b, packed_color4, 1);
1154
1155 pInten_modifer_table = &rg_etc1_inten_tables[table_idx][0];
1156 rg_etc1_block_sublock_diff(dst, pInten_modifer_table, r, g, b);
1157}
1158
1159// This is the exported function to unpack a block
1160bool
1161rg_etc1_unpack_block(const void *ETC1_block, unsigned int *pixels, bool preserve_alpha)
1162{
1163 unsigned char diff_flag, flip_flag, table_index0, table_index1;
1164 unsigned int subblock_colors0[4];
1165 unsigned int subblock_colors1[4];
1166 unsigned char x, y;
1167 unsigned char success = 1;
1168
1169 diff_flag = rg_etc1_block_diff_bit_get(ETC1_block);
1170 flip_flag = rg_etc1_block_flip_bit_get(ETC1_block);
1171 table_index0 = rg_etc1_block_inten_table_get(ETC1_block, 0);
1172 table_index1 = rg_etc1_block_inten_table_get(ETC1_block, 1);
1173
1174 if (diff_flag)
1175 {
1176 unsigned short base_color5, delta_color3;
1177
1178 base_color5 = rg_etc1_block_base5_color_get(ETC1_block);
1179 delta_color3 = rg_etc1_block_delta3_color_get(ETC1_block);
1180
1181 rg_etc1_block_subblock_color5_diff_get(subblock_colors0, base_color5, table_index0);
1182 success = rg_etc1_block_subblock_color5_delta3_diff_get(subblock_colors1,
1183 base_color5, delta_color3,
1184 table_index1);
1185 }
1186 else
1187 {
1188 unsigned short base_color4_0, base_color4_1;
1189
1190 base_color4_0 = rg_etc_block_base4_color_get(ETC1_block, 0);
1191 base_color4_1 = rg_etc_block_base4_color_get(ETC1_block, 1);
1192
1193 rg_etc1_block_subblock_color4_abs_get(subblock_colors0, base_color4_0, table_index0);
1194 rg_etc1_block_subblock_color4_abs_get(subblock_colors1, base_color4_1, table_index1);
1195 }
1196
1197 // FIXME: preserve_alpha and continue
1198 // Block is either :
1199 // 0000
1200 // 0000
1201 // 1111
1202 // 1111
1203 // or :
1204 // 0011
1205 // 0011
1206 // 0011
1207 // 0011
1208 // Depending on flip_flag.
1209
1210 if (flip_flag)
1211 {
1212 for (y = 0; y < 2; y++)
1213 {
1214 for (x = 0; x < 4; x++)
1215 pixels[x] = rg_etc1_color_quad_set(pixels[x],
1216 subblock_colors0[rg_etc1_block_selector_get(ETC1_block, x, y)],
1217 preserve_alpha);
1218 pixels += 4;
1219 }
1220
1221 for (y = 2; y < 4; y++)
1222 {
1223 for (x = 0; x < 4; x++)
1224 pixels[x] = rg_etc1_color_quad_set(pixels[x],
1225 subblock_colors1[rg_etc1_block_selector_get(ETC1_block, x, y)],
1226 preserve_alpha);
1227 pixels += 4;
1228 }
1229 }
1230 else
1231 {
1232 for (y = 0; y < 4; y++)
1233 {
1234 for (x = 0; x < 2; x++)
1235 pixels[x] = rg_etc1_color_quad_set(pixels[x],
1236 subblock_colors0[rg_etc1_block_selector_get(ETC1_block, x, y)],
1237 preserve_alpha);
1238 for (; x < 4; x++)
1239 pixels[x] = rg_etc1_color_quad_set(pixels[x],
1240 subblock_colors1[rg_etc1_block_selector_get(ETC1_block, x, y)],
1241 preserve_alpha);
1242
1243 pixels += 4;
1244 }
1245 }
1246
1247 return success;
1248}
1249
1250// NOTE: Most of the following loop could be unrolled, but for sanity and readability, I did
1251// prefer to stick to simpler solution.
1252static inline unsigned int *
1253rg_etc1_indirect_radix_sort(unsigned int num_indices, unsigned int pIndices0[8], unsigned int pIndices1[8],
1254 const unsigned short pKeys[8], unsigned int key_ofs, unsigned char key_size,
1255 unsigned char init_indices)
1256{
1257 unsigned int hist[256 * 4];
1258 unsigned int *p;
1259 unsigned int *q;
1260 unsigned int *pCur;
1261 unsigned int *pNew;
1262 unsigned int key;
1263 unsigned int pass;
1264
1265 assert((key_ofs >= 0) && (key_ofs < sizeof(pIndices0)));
1266 assert((key_size >= 1) && (key_size <= 4));
1267
1268 if (init_indices)
1269 {
1270 unsigned int i;
1271
1272 p = pIndices0;
1273 for (i = 0; i < num_indices; p++, i++)
1274 *p = i;
1275 }
1276
1277 memset(hist, 0, sizeof (hist));
1278
1279#define RG_ETC1_GET_KEY(p) (*(const unsigned int*)((const unsigned char*)(pKeys + *(p)) + key_ofs))
1280#define RG_ETC1_GET_KEY_FROM_INDEX(i) (*(const unsigned int*)((const unsigned char*)(pKeys + (i)) + key_ofs))
1281
1282 switch (key_size)
1283 {
1284 case 4:
1285 p = pIndices0;
1286 q = pIndices0 + num_indices;
1287
1288 for (; p != q; p++)
1289 {
1290 key = RG_ETC1_GET_KEY(p);
1291
1292 hist[ key & 0xFF]++;
1293 hist[256 + ((key >> 8) & 0xFF)]++;
1294 hist[512 + ((key >> 16) & 0xFF)]++;
1295 hist[768 + ((key >> 24) & 0xFF)]++;
1296 }
1297 break;
1298 case 3:
1299 p = pIndices0;
1300 q = pIndices0 + num_indices;
1301
1302 for ( ; p != q; p++)
1303 {
1304 key = RG_ETC1_GET_KEY(p);
1305
1306 hist[ key & 0xFF]++;
1307 hist[256 + ((key >> 8) & 0xFF)]++;
1308 hist[512 + ((key >> 16) & 0xFF)]++;
1309 }
1310 break;
1311 case 2:
1312 p = pIndices0;
1313 q = pIndices0 + num_indices;
1314
1315 for ( ; p != q; p++)
1316 {
1317 key = RG_ETC1_GET_KEY(p);
1318
1319 hist[ key & 0xFF]++;
1320 hist[256 + ((key >> 8) & 0xFF)]++;
1321 }
1322 break;
1323 case 1:
1324 p = pIndices0;
1325 q = pIndices0 + num_indices;
1326
1327 for ( ; p != q; p++)
1328 {
1329 key = RG_ETC1_GET_KEY(p);
1330
1331 hist[key & 0xFF]++;
1332 }
1333 break;
1334 default:
1335 abort();
1336 }
1337
1338 pCur = pIndices0;
1339 pNew = pIndices1;
1340
1341 for (pass = 0; pass < key_size; pass++)
1342 {
1343 unsigned int offsets[256];
1344 const unsigned int *pHist = &hist[pass << 8];
1345 unsigned int *t;
1346 unsigned int cur_ofs = 0;
1347 unsigned int i;
1348 unsigned int pass_shift = pass << 3;
1349
1350 for (i = 0; i < 256; i++)
1351 {
1352 offsets[i] = cur_ofs;
1353 cur_ofs += pHist[i];
1354 }
1355
1356 q = pCur + num_indices;
1357 for (p = pCur; p != q; p++)
1358 {
1359 unsigned int dst_offset;
1360 unsigned int idx = p[0];
1361 unsigned int c = (RG_ETC1_GET_KEY_FROM_INDEX(idx) >> pass_shift) & 0xFF;
1362
1363 dst_offset = offsets[c]++;
1364 pNew[dst_offset] = idx;
1365 }
1366
1367 t = pCur;
1368 pCur = pNew;
1369 pNew = t;
1370 }
1371
1372 return pCur;
1373}
1374
1375typedef struct _Etc1_Solution_Coordinates Etc1_Solution_Coordinates;
1376struct _Etc1_Solution_Coordinates
1377{
1378 color_quad_u8 m_unscaled_color;
1379 unsigned int m_inten_table;
1380 unsigned char m_color4;
1381};
1382
1383static inline void
1384rg_etc1_solution_coordinates_component_set(Etc1_Solution_Coordinates *solution,
1385 int r, int g, int b,
1386 unsigned int inten_table, unsigned char color4)
1387{
1388 rg_etc1_color_quad_u8_init(&solution->m_unscaled_color, r, g, b, 255);
1389 solution->m_inten_table = inten_table;
1390 solution->m_color4 = color4;
1391}
1392
1393static inline void
1394rg_etc1_solution_coordinates_set(Etc1_Solution_Coordinates *solution,
1395 color_quad_u8 unscaled_color, unsigned int inten_table, unsigned char color4)
1396{
1397 rg_etc1_color_quad_u8_copy(&solution->m_unscaled_color, &unscaled_color);
1398 solution->m_inten_table = inten_table;
1399 solution->m_color4 = color4;
1400}
1401
1402static inline void
1403rg_etc1_solution_coordinates_clear(Etc1_Solution_Coordinates *solution)
1404{
1405 memset(solution, 0, sizeof (Etc1_Solution_Coordinates));
1406}
1407
1408static inline void
1409rg_etc1_solution_coordinates_component_get(const Etc1_Solution_Coordinates *solution,
1410 unsigned char *r, unsigned char *g, unsigned char *b)
1411{
1412 *r = solution->m_unscaled_color.comp.r;
1413 *g = solution->m_unscaled_color.comp.g;
1414 *b = solution->m_unscaled_color.comp.b;
1415
1416 if (solution->m_color4)
1417 {
1418 *r = *r | (*r << 4);
1419 *g = *g | (*g << 4);
1420 *b = *b | (*b << 4);
1421 }
1422 else
1423 {
1424 *r = (*r >> 2) | (*r << 3);
1425 *g = (*g >> 2) | (*g << 3);
1426 *b = (*b >> 2) | (*b << 3);
1427 }
1428}
1429
1430static inline void
1431rg_etc1_solution_coordinates_get_scaled_color(color_quad_u8 *color, const Etc1_Solution_Coordinates *coords)
1432{
1433 unsigned char br, bg, bb;
1434
1435 rg_etc1_solution_coordinates_component_get(coords, &br, &bg, &bb);
1436
1437 rg_etc1_color_quad_u8_init(color,br, bg, bb, 255);
1438
1439}
1440
1441static inline void
1442rg_etc1_solution_coordinates_block_colors_get(const Etc1_Solution_Coordinates *coords, color_quad_u8 colors[4])
1443{
1444 const int* pInten_table = rg_etc1_inten_tables[coords->m_inten_table];
1445 unsigned char i;
1446 unsigned char br, bg, bb;
1447
1448 rg_etc1_solution_coordinates_component_get(coords, &br, &bg, &bb);
1449
1450 for (i = 0; i < 4; i++)
1451 rg_etc1_color_quad_u8_init(&colors[i], br + pInten_table[i], bg + pInten_table[i], bb + pInten_table[i], 255);
1452}
1453
1454static inline void
1455rg_etc1_pack_params_clear(rg_etc1_pack_params *params)
1456{
1457 params->m_quality = rg_etc1_high_quality;
1458 params->m_dithering = false;
1459}
1460
1461static const int rg_etc1_default_scan_delta[] = { 0 };
1462
1463typedef struct _rg_etc1_optimizer_params rg_etc1_optimizer_params;
1464struct _rg_etc1_optimizer_params
1465{
1466 rg_etc1_pack_params *base_params;
1467 uint m_num_src_pixels;
1468 const color_quad_u8* m_pSrc_pixels;
1469
1470 bool m_use_color4;
1471 const int* m_pScan_deltas;
1472 uint m_scan_delta_size;
1473
1474 color_quad_u8 m_base_color5;
1475 bool m_constrain_against_base_color5;
1476};
1477
1478static inline void
1479rg_etc1_optimizer_params_clean(rg_etc1_optimizer_params *params)
1480{
1481 params->m_num_src_pixels = 0;
1482 params->m_pSrc_pixels = 0;
1483
1484 params->m_use_color4 = false;
1485 params->m_pScan_deltas = rg_etc1_default_scan_delta;
1486 params->m_scan_delta_size = 1;
1487
1488 rg_etc1_color_quad_u8_clear(&params->m_base_color5);
1489 params->m_constrain_against_base_color5 = false;
1490}
1491
1492static inline void
1493rg_etc1_optimizer_params_base_clear(rg_etc1_optimizer_params *params)
1494{
1495 rg_etc1_pack_params_clear(params->base_params);
1496 rg_etc1_optimizer_params_clean(params);
1497}
1498
1499typedef struct
1500{
1501 uint64 m_error;
1502 color_quad_u8 m_block_color_unscaled;
1503 uint m_block_inten_table;
1504 uint m_n;
1505 uint8* m_pSelectors;
1506 bool m_block_color4;
1507} rg_etc1_optimizer_results;
1508
1509static inline void
1510rg_etc1_optimizer_results_duplicate(rg_etc1_optimizer_results *dst, const rg_etc1_optimizer_results *src)
1511{
1512 rg_etc1_color_quad_u8_copy(&dst->m_block_color_unscaled,&src->m_block_color_unscaled);
1513 dst->m_block_color4 = src->m_block_color4;
1514 dst->m_block_inten_table = src->m_block_inten_table;
1515 dst->m_error = src->m_error;
1516 RG_ETC1_ASSERT(dst->m_n == src->m_n);
1517 memcpy(dst->m_pSelectors, src->m_pSelectors, src->m_n);
1518}
1519
1520typedef struct
1521{
1522 Etc1_Solution_Coordinates m_coords;
1523 uint8 m_selectors[8];
1524 uint64 m_error;
1525 bool m_valid;
1526} rg_etc1_potential_solution;
1527
1528static inline void
1529rg_etc1_potential_solution_clear(rg_etc1_potential_solution *solution)
1530{
1531 rg_etc1_solution_coordinates_clear(&solution->m_coords);
1532 solution->m_error = cUINT64_MAX;
1533 solution->m_valid = false;
1534}
1535
1536typedef struct
1537{
1538 const rg_etc1_optimizer_params* m_pParams;
1539 rg_etc1_optimizer_results* m_pResult;
1540
1541 int m_limit;
1542
1543 float m_avg_color[3];
1544 int m_br, m_bg, m_bb;
1545 uint16 m_luma[8];
1546 uint32 m_sorted_luma[2][8];
1547 const uint32* m_pSorted_luma_indices;
1548 uint32* m_pSorted_luma;
1549
1550 uint8 m_selectors[8];
1551 uint8 m_best_selectors[8];
1552
1553 rg_etc1_potential_solution m_best_solution;
1554 rg_etc1_potential_solution m_trial_solution;
1555 uint8 m_temp_selectors[8];
1556}rg_etc1_optimizer;
1557
1558static inline void
1559rg_etc1_optimizer_clear(rg_etc1_optimizer *optimizer)
1560{
1561 optimizer->m_pParams = NULL;
1562 optimizer->m_pResult = NULL;
1563 optimizer->m_pSorted_luma = NULL;
1564 optimizer->m_pSorted_luma_indices = NULL;
1565 optimizer->m_br = optimizer->m_bg = optimizer->m_bb = 0;
1566 rg_etc1_potential_solution_clear(&optimizer->m_best_solution);
1567 rg_etc1_potential_solution_clear(&optimizer->m_trial_solution);
1568}
1569
1570static bool rg_etc1_optimizer_evaluate_solution(rg_etc1_optimizer *optimizer, const Etc1_Solution_Coordinates* coords,
1571 rg_etc1_potential_solution* trial_solution,
1572 rg_etc1_potential_solution* pBest_solution);
1573static bool rg_etc1_optimizer_evaluate_solution_fast(rg_etc1_optimizer *optimizer,const Etc1_Solution_Coordinates *coords,
1574 rg_etc1_potential_solution *trial_solution,
1575 rg_etc1_potential_solution *pBest_solution);
1576
1577static bool
1578rg_etc1_optimizer_compute(rg_etc1_optimizer *optimizer)
1579{
1580 const uint n = optimizer->m_pParams->m_num_src_pixels;
1581 const int scan_delta_size = optimizer->m_pParams->m_scan_delta_size;
1582 int zdi;
1583
1584 // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
1585 // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
1586 for (zdi = 0; zdi < scan_delta_size; zdi++)
1587 {
1588 const int zd = optimizer->m_pParams->m_pScan_deltas[zdi];
1589 const int mbb = optimizer->m_bb + zd;
1590 int ydi;
1591 if (mbb < 0) continue; else if (mbb > optimizer->m_limit) break;
1592
1593 for (ydi = 0; ydi < scan_delta_size; ydi++)
1594 {
1595 const int yd = optimizer->m_pParams->m_pScan_deltas[ydi];
1596 const int mbg = optimizer->m_bg + yd;
1597 int xdi;
1598
1599 if (mbg < 0) continue; else if (mbg > optimizer->m_limit) break;
1600
1601 for (xdi = 0; xdi < scan_delta_size; xdi++)
1602 {
1603 const int xd = optimizer->m_pParams->m_pScan_deltas[xdi];
1604 const int mbr = optimizer->m_br + xd;
1605 Etc1_Solution_Coordinates coords;
1606 uint max_refinement_trials;
1607 uint refinement_trial;
1608
1609 rg_etc1_solution_coordinates_component_set(&coords, mbr, mbg, mbb, 0, optimizer->m_pParams->m_use_color4);
1610 if (mbr < 0) continue; else if (mbr > optimizer->m_limit) break;
1611
1612 if (optimizer->m_pParams->base_params->m_quality == rg_etc1_high_quality)
1613 {
1614 if (!rg_etc1_optimizer_evaluate_solution(optimizer, &coords, &optimizer->m_trial_solution, &optimizer->m_best_solution))
1615 continue;
1616 }
1617 else
1618 {
1619 if (!rg_etc1_optimizer_evaluate_solution_fast(optimizer, &coords, &optimizer->m_trial_solution, &optimizer->m_best_solution))
1620 continue;
1621 }
1622
1623 // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
1624 // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
1625 // The goal is:
1626 // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
1627 // Rearranging this:
1628 // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
1629 // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
1630 // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
1631 // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
1632 // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
1633 // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
1634 // So what this means:
1635 // optimal_block_color = avg_input - avg_inten_delta
1636 // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
1637 // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
1638 // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.
1639
1640 max_refinement_trials = (optimizer->m_pParams->base_params->m_quality == rg_etc1_low_quality) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2);
1641 for (refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
1642 {
1643 const uint8* pSelectors = optimizer->m_best_solution.m_selectors;
1644 const int* pInten_table = rg_etc1_inten_tables[optimizer->m_best_solution.m_coords.m_inten_table];
1645
1646 int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
1647 uint index;
1648 color_quad_u8 base_color;
1649 float avg_delta_r_f, avg_delta_g_f, avg_delta_b_f;
1650 int br1, bg1, bb1;
1651 bool skip;
1652 Etc1_Solution_Coordinates coords1;
1653 rg_etc1_solution_coordinates_get_scaled_color(&base_color, &optimizer->m_best_solution.m_coords);
1654
1655 for (index = 0; index < n; index++)
1656 {
1657 const uint s = *pSelectors++;
1658 const int yd = pInten_table[s];
1659 // Compute actual delta being applied to each pixel, taking into account clamping.
1660 delta_sum_r += CLAMP(base_color.comp.r + yd, 0, 255) - base_color.comp.r;
1661 delta_sum_g += CLAMP(base_color.comp.g + yd, 0, 255) - base_color.comp.g;
1662 delta_sum_b += CLAMP(base_color.comp.b + yd, 0, 255) - base_color.comp.b;
1663 }
1664 if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
1665 break;
1666 avg_delta_r_f = (float)(delta_sum_r) / n;
1667 avg_delta_g_f = (float)(delta_sum_g) / n;
1668 avg_delta_b_f = (float)(delta_sum_b) / n;
1669 br1 = (uint)CLAMP(((optimizer->m_avg_color[0] - avg_delta_r_f) * optimizer->m_limit / 255.0f + .5f),
1670 0, optimizer->m_limit);
1671 bg1 = (uint)CLAMP(((optimizer->m_avg_color[1] - avg_delta_g_f) * optimizer->m_limit / 255.0f + .5f),
1672 0, optimizer->m_limit);
1673 bb1 = (uint)CLAMP(((optimizer->m_avg_color[2] - avg_delta_b_f) * optimizer->m_limit / 255.0f + .5f),
1674 0, optimizer->m_limit);
1675 skip = false;
1676
1677 if ((mbr == br1) && (mbg == bg1) && (mbb == bb1)) {
1678 skip = true;
1679 } else if ((br1 == optimizer->m_best_solution.m_coords.m_unscaled_color.comp.r) &&
1680 (bg1 == optimizer->m_best_solution.m_coords.m_unscaled_color.comp.g) &&
1681 (bb1 == optimizer->m_best_solution.m_coords.m_unscaled_color.comp.b)) {
1682 skip = true;
1683 } else if ((optimizer->m_br == br1) && (optimizer->m_bg == bg1) && (optimizer->m_bb == bb1)) {
1684 skip = true;
1685 }
1686
1687 if (skip)
1688 break;
1689
1690 rg_etc1_solution_coordinates_component_set(&coords1, br1, bg1, bb1, 0, optimizer->m_pParams->m_use_color4);
1691 if (optimizer->m_pParams->base_params->m_quality == rg_etc1_high_quality)
1692 {
1693 if (!rg_etc1_optimizer_evaluate_solution(optimizer, &coords1, &optimizer->m_trial_solution, &optimizer->m_best_solution))
1694 break;
1695 }
1696 else
1697 {
1698 if (!rg_etc1_optimizer_evaluate_solution_fast(optimizer, &coords1, &optimizer->m_trial_solution, &optimizer->m_best_solution))
1699 break;
1700 }
1701
1702 } // refinement_trial
1703
1704 } // xdi
1705 } // ydi
1706 } // zdi
1707
1708 if (!optimizer->m_best_solution.m_valid)
1709 {
1710 optimizer->m_pResult->m_error = cUINT32_MAX;
1711 return false;
1712 }
1713
1714#ifdef RG_ETC1_BUILD_DEBUG
1715 {
1716 color_quad_u8 block_colors[4];
1717 const color_quad_u8* pSrc_pixels;
1718 uint64 actual_error=0;
1719 uint i;
1720 const uint8* pSelectors = optimizer->m_best_solution.m_selectors;
1721
1722 rg_etc1_solution_coordinates_block_colors_get(optimizer->m_best_solution., block_colors);
1723 pSrc_pixels = optimizer->m_pParams->m_pSrc_pixels;
1724 for (i = 0; i < n; i++)
1725 actual_error += rg_etc1_color_quad_u8_rgb_squared_distance(pSrc_pixels[i], block_colors[pSelectors[i]]);
1726
1727 RG_ETC1_ASSERT(actual_error == optimizer->m_best_solution.m_error);
1728 }
1729#endif
1730
1731 optimizer->m_pResult->m_error = optimizer->m_best_solution.m_error;
1732 rg_etc1_color_quad_u8_copy(&optimizer->m_pResult->m_block_color_unscaled,&optimizer->m_best_solution.m_coords.m_unscaled_color);
1733 optimizer->m_pResult->m_block_color4 = optimizer->m_best_solution.m_coords.m_color4;
1734 optimizer->m_pResult->m_block_inten_table = optimizer->m_best_solution.m_coords.m_inten_table;
1735 memcpy(optimizer->m_pResult->m_pSelectors, optimizer->m_best_solution.m_selectors, n);
1736 optimizer->m_pResult->m_n = n;
1737
1738 return true;
1739}
1740
1741void
1742rg_etc1_optimizer_init(rg_etc1_optimizer *optimizer, const rg_etc1_optimizer_params *params,
1743 rg_etc1_optimizer_results *result)
1744{
1745 // This version is hardcoded for 8 pixel subblocks.
1746 RG_ETC1_ASSERT(params->m_num_src_pixels == 8);
1747
1748 const uint n = 8;
1749 uint i;
1750 float avg_color[3];
1751 float fc[3];
1752
1753 optimizer->m_pParams = params;
1754 optimizer->m_pResult = result;
1755
1756 rg_etc1_vec_init(avg_color, 0.0f);
1757 optimizer->m_limit = optimizer->m_pParams->m_use_color4 ? 15 : 31;
1758
1759 for ( i = 0; i < n; i++)
1760 {
1761 const color_quad_u8 *c = &optimizer->m_pParams->m_pSrc_pixels[i];
1762 rg_etc1_vec_set(fc, c->comp.r, c->comp.g, c->comp.b);
1763
1764 rg_etc1_vec_add(avg_color,fc);
1765
1766 optimizer->m_luma[i] = (uint16)(c->comp.r + c->comp.g + c->comp.b);
1767 optimizer->m_sorted_luma[0][i] = i;
1768 }
1769 rg_etc1_vec_scale(avg_color, (1.0f/(float)(n)));
1770 rg_etc1_vec_copy(optimizer->m_avg_color,avg_color);
1771
1772 optimizer->m_br = CLAMP((uint)(optimizer->m_avg_color[0] * optimizer->m_limit / 255.0f + .5f), 0, optimizer->m_limit);
1773 optimizer->m_bg = CLAMP((uint)(optimizer->m_avg_color[1] * optimizer->m_limit / 255.0f + .5f), 0, optimizer->m_limit);
1774 optimizer->m_bb = CLAMP((uint)(optimizer->m_avg_color[2] * optimizer->m_limit / 255.0f + .5f), 0, optimizer->m_limit);
1775
1776 if (optimizer->m_pParams->base_params->m_quality <= rg_etc1_medium_quality)
1777 {
1778 optimizer->m_pSorted_luma_indices = rg_etc1_indirect_radix_sort(n, optimizer->m_sorted_luma[0],
1779 optimizer->m_sorted_luma[1], optimizer->m_luma,
1780 0, sizeof(optimizer->m_luma[0]), false);
1781 optimizer->m_pSorted_luma = optimizer->m_sorted_luma[0];
1782
1783 if (optimizer->m_pSorted_luma_indices == optimizer->m_sorted_luma[0])
1784 optimizer->m_pSorted_luma = optimizer->m_sorted_luma[1];
1785
1786 for (i = 0; i < n; i++)
1787 optimizer->m_pSorted_luma[i] = optimizer->m_luma[optimizer->m_pSorted_luma_indices[i]];
1788 }
1789
1790 rg_etc1_solution_coordinates_clear(&optimizer->m_best_solution.m_coords);
1791 optimizer->m_best_solution.m_valid = false;
1792 optimizer->m_best_solution.m_error = cUINT64_MAX;
1793}
1794
1795static bool
1796rg_etc1_optimizer_evaluate_solution(rg_etc1_optimizer *optimizer, const Etc1_Solution_Coordinates* coords,
1797 rg_etc1_potential_solution* trial_solution, rg_etc1_potential_solution* pBest_solution)
1798{
1799 color_quad_u8 base_color;
1800 const uint n = 8;
1801 uint inten_table;
1802 bool success = false;
1803
1804 trial_solution->m_valid = false;
1805
1806 if (optimizer->m_pParams->m_constrain_against_base_color5)
1807 {
1808 int dr, dg, db;
1809 dr = coords->m_unscaled_color.comp.r - optimizer->m_pParams->m_base_color5.comp.r;
1810 dg = coords->m_unscaled_color.comp.g - optimizer->m_pParams->m_base_color5.comp.g;
1811 db = coords->m_unscaled_color.comp.b - optimizer->m_pParams->m_base_color5.comp.b;
1812
1813 if ((MIN(MIN(dr,dg),db) < cETC1ColorDeltaMin) || (MAX(MAX(dr,dg),db) > cETC1ColorDeltaMax))
1814 return false;
1815 }
1816
1817 rg_etc1_solution_coordinates_get_scaled_color(&base_color, coords);
1818 trial_solution->m_error = cUINT64_MAX;
1819
1820 for (inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++)
1821 {
1822 const int* pInten_table = rg_etc1_inten_tables[inten_table];
1823 uint64 total_error = 0;
1824 color_quad_u8 block_colors[4];
1825 const color_quad_u8* pSrc_pixels = optimizer->m_pParams->m_pSrc_pixels;
1826
1827 uint c;
1828 for (c = 0; c < 4; c++)
1829 {
1830 const int yd = pInten_table[c];
1831 rg_etc1_color_quad_u8_init(&block_colors[c], base_color.comp.r+yd, base_color.comp.g+yd, base_color.comp.b+yd, 0);
1832 }
1833
1834 for (c = 0; c < n; c++)
1835 {
1836 uint best_selector_index = 0, best_error, trial_error;
1837 const color_quad_u8* src_pixel = pSrc_pixels++;
1838
1839 best_error = SQUARE((src_pixel->comp.r - block_colors[0].comp.r)) +
1840 SQUARE((src_pixel->comp.g - block_colors[0].comp.g)) +
1841 SQUARE((src_pixel->comp.b - block_colors[0].comp.b));
1842 trial_error = SQUARE((src_pixel->comp.r - block_colors[1].comp.r)) +
1843 SQUARE((src_pixel->comp.g - block_colors[1].comp.g)) +
1844 SQUARE((src_pixel->comp.b - block_colors[1].comp.b));
1845 if (trial_error < best_error)
1846 {
1847 best_error = trial_error;
1848 best_selector_index = 1;
1849 }
1850
1851 trial_error = SQUARE((src_pixel->comp.r - block_colors[2].comp.r)) +
1852 SQUARE((src_pixel->comp.g - block_colors[2].comp.g)) +
1853 SQUARE((src_pixel->comp.b - block_colors[2].comp.b));
1854 if (trial_error < best_error)
1855 {
1856 best_error = trial_error;
1857 best_selector_index = 2;
1858 }
1859
1860 trial_error = SQUARE((src_pixel->comp.r - block_colors[3].comp.r)) +
1861 SQUARE((src_pixel->comp.g - block_colors[3].comp.g)) +
1862 SQUARE((src_pixel->comp.b - block_colors[3].comp.b));
1863 if (trial_error < best_error)
1864 {
1865 best_error = trial_error;
1866 best_selector_index = 3;
1867 }
1868
1869 optimizer->m_temp_selectors[c] = (uint8)(best_selector_index);
1870
1871 total_error += best_error;
1872 if (total_error >= trial_solution->m_error)
1873 break;
1874 }
1875
1876 if (total_error < trial_solution->m_error)
1877 {
1878 trial_solution->m_error = total_error;
1879 trial_solution->m_coords.m_inten_table = inten_table;
1880 memcpy(trial_solution->m_selectors, optimizer->m_temp_selectors, 8);
1881 trial_solution->m_valid = true;
1882 }
1883 }
1884 rg_etc1_color_quad_u8_copy(&trial_solution->m_coords.m_unscaled_color,&coords->m_unscaled_color);
1885 trial_solution->m_coords.m_color4 = optimizer->m_pParams->m_use_color4;
1886
1887 if (pBest_solution)
1888 {
1889 if (trial_solution->m_error < pBest_solution->m_error)
1890 {
1891 memcpy(pBest_solution,trial_solution,sizeof(rg_etc1_potential_solution));
1892 success = true;
1893 }
1894 }
1895
1896 return success;
1897}
1898
1899static bool
1900rg_etc1_optimizer_evaluate_solution_fast(rg_etc1_optimizer *optimizer, const Etc1_Solution_Coordinates *coords,
1901 rg_etc1_potential_solution *trial_solution, rg_etc1_potential_solution *pBest_solution)
1902{
1903 color_quad_u8 base_color;
1904 const uint n = 8;
1905 int inten_table;
1906 bool success = false;
1907
1908 if (optimizer->m_pParams->m_constrain_against_base_color5)
1909 {
1910 int dr, dg, db;
1911 dr = coords->m_unscaled_color.comp.r - optimizer->m_pParams->m_base_color5.comp.r;
1912 dg = coords->m_unscaled_color.comp.g - optimizer->m_pParams->m_base_color5.comp.g;
1913 db = coords->m_unscaled_color.comp.b - optimizer->m_pParams->m_base_color5.comp.b;
1914
1915
1916 if ((MIN(MIN(dr,dg),db) < cETC1ColorDeltaMin) || (MAX(MAX(dr,dg),db) > cETC1ColorDeltaMax))
1917 {
1918 trial_solution->m_valid = false;
1919 return false;
1920 }
1921 }
1922
1923 rg_etc1_solution_coordinates_get_scaled_color(&base_color,coords);
1924
1925 trial_solution->m_error = cUINT64_MAX;
1926
1927 for (inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table)
1928 {
1929 const int* pInten_table = rg_etc1_inten_tables[inten_table];
1930 uint block_inten[4];
1931 color_quad_u8 block_colors[4];
1932 uint block_inten_midpoints[3];
1933 uint64 total_error = 0;
1934 const color_quad_u8* pSrc_pixels = optimizer->m_pParams->m_pSrc_pixels;
1935 uint s, c;
1936
1937 for (s = 0; s < 4; s++)
1938 {
1939 const int yd = pInten_table[s];
1940 rg_etc1_color_quad_u8_init(&block_colors[s], base_color.comp.r+yd, base_color.comp.g+yd, base_color.comp.b+yd, 0);
1941 block_inten[s] = block_colors[s].comp.r + block_colors[s].comp.g + block_colors[s].comp.b;
1942 }
1943
1944 // evaluate_solution_fast() enforces/assumesd a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors.
1945 // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast.
1946 // 0 1 2 3
1947 // 01 12 23
1948 block_inten_midpoints[0] = block_inten[0] + block_inten[1];
1949 block_inten_midpoints[1] = block_inten[1] + block_inten[2];
1950 block_inten_midpoints[2] = block_inten[2] + block_inten[3];
1951
1952 if ((optimizer->m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
1953 {
1954 if (block_inten[0] > optimizer->m_pSorted_luma[n - 1])
1955 {
1956 const uint min_error = labs(block_inten[0] - optimizer->m_pSorted_luma[n - 1]);
1957 if (min_error >= trial_solution->m_error)
1958 continue;
1959 }
1960
1961 memset(&optimizer->m_temp_selectors[0], 0, n);
1962
1963 for (c = 0; c < n; c++) {
1964 total_error += rg_etc1_color_quad_u8_rgb_squared_distance(block_colors[0], pSrc_pixels[c]);
1965 }
1966 }
1967 else if ((optimizer->m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
1968 {
1969 if (optimizer->m_pSorted_luma[0] > block_inten[3])
1970 {
1971 const uint min_error = labs(optimizer->m_pSorted_luma[0] - block_inten[3]);
1972 if (min_error >= trial_solution->m_error)
1973 continue;
1974 }
1975
1976 memset(&optimizer->m_temp_selectors[0], 3, n);
1977
1978 for (c = 0; c < n; c++)
1979 total_error += rg_etc1_color_quad_u8_rgb_squared_distance(block_colors[3], pSrc_pixels[c]);
1980 }
1981 else
1982 {
1983 uint cur_selector = 0;
1984 for (c = 0; c < n; c++)
1985 {
1986 const uint y = optimizer->m_pSorted_luma[c];
1987 while ((y * 2) >= block_inten_midpoints[cur_selector])
1988 if (++cur_selector > 2)
1989 goto done;
1990 const uint sorted_pixel_index = optimizer->m_pSorted_luma_indices[c];
1991 optimizer->m_temp_selectors[sorted_pixel_index] = (uint8)(cur_selector);
1992 total_error += rg_etc1_color_quad_u8_rgb_squared_distance(block_colors[cur_selector],
1993 pSrc_pixels[sorted_pixel_index]);
1994 }
1995 done:
1996 while (c < n)
1997 {
1998 const uint sorted_pixel_index = optimizer->m_pSorted_luma_indices[c];
1999 optimizer->m_temp_selectors[sorted_pixel_index] = 3;
2000 total_error += rg_etc1_color_quad_u8_rgb_squared_distance(block_colors[3], pSrc_pixels[sorted_pixel_index]);
2001 ++c;
2002 }
2003 }
2004
2005 if (total_error < trial_solution->m_error)
2006 {
2007 trial_solution->m_error = total_error;
2008 trial_solution->m_coords.m_inten_table = inten_table;
2009 memcpy(trial_solution->m_selectors, optimizer->m_temp_selectors, n);
2010 trial_solution->m_valid = true;
2011 if (!total_error)
2012 break;
2013 }
2014 }
2015 rg_etc1_color_quad_u8_copy(&trial_solution->m_coords.m_unscaled_color,&coords->m_unscaled_color);
2016 trial_solution->m_coords.m_color4 = optimizer->m_pParams->m_use_color4;
2017
2018 if (pBest_solution)
2019 {
2020 if (trial_solution->m_error < pBest_solution->m_error)
2021 {
2022 memcpy(pBest_solution,trial_solution,sizeof(rg_etc1_potential_solution));
2023 success = true;
2024 }
2025 }
2026
2027 return success;
2028}
2029
2030static uint
2031etc1_decode_value(uint diff, uint inten, uint selector, uint packed_c)
2032{
2033 const uint limit = diff ? 32 : 16;
2034 RG_ETC1_ASSERT((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit));
2035 int c;
2036 if (diff)
2037 c = (packed_c >> 2) | (packed_c << 3);
2038 else
2039 c = packed_c | (packed_c << 4);
2040 c += rg_etc1_inten_tables[inten][selector];
2041 c = CLAMP(c, 0, 255);
2042 return c;
2043}
2044
2045static inline int mul_8bit(int a, int b) { int t = a*b + 128; return (t + (t >> 8)) >> 8; }
2046
2047void rg_etc1_pack_block_init()
2048{
2049 uint diff;
2050 uint expand5[32];
2051 int i;
2052 for (diff = 0; diff < 2; diff++)
2053 {
2054 const uint limit = diff ? 32 : 16;
2055 uint inten;
2056
2057 for (inten = 0; inten < 8; inten++)
2058 {
2059 uint selector;
2060 for (selector = 0; selector < 4; selector++)
2061 {
2062 const uint inverse_table_index = diff + (inten << 1) + (selector << 4);
2063 uint color;
2064 for (color = 0; color < 256; color++)
2065 {
2066 uint best_error = cUINT32_MAX, best_packed_c = 0;
2067 uint packed_c;
2068 for (packed_c = 0; packed_c < limit; packed_c++)
2069 {
2070 int v = etc1_decode_value(diff, inten, selector, packed_c);
2071 uint err = labs(v - (int)color);
2072 if (err < best_error)
2073 {
2074 best_error = err;
2075 best_packed_c = packed_c;
2076 if (!best_error)
2077 break;
2078 }
2079 }
2080 RG_ETC1_ASSERT(best_error <= 255);
2081 rg_etc1_inverse_lookup[inverse_table_index][color] = (uint16)(best_packed_c | (best_error << 8));
2082 }
2083 }
2084 }
2085 }
2086
2087 for(i = 0; i < 32; i++)
2088 expand5[i] = (i << 3) | (i >> 2);
2089
2090 for(i = 0; i < 256 + 16; i++)
2091 {
2092 int v = (int)CLAMP(i - 8, 0, 255);
2093 rg_etc_quant5_tab[i] = (uint8)(expand5[mul_8bit(v,31)]);
2094 }
2095}
2096
2097// Packs solid color blocks efficiently using a set of small precomputed tables.
2098// For random 888 inputs, MSE results are better than Erricson's ETC1 packer in "slow" mode ~9.5% of the time, is slightly worse only ~.01% of the time, and is equal the rest of the time.
2099static uint64
2100rg_etc1_pack_block_solid_color(unsigned char *block, const uint8* pColor, rg_etc1_pack_params *pack_params)
2101{
2102 RG_ETC1_ASSERT(rg_etc1_inverse_lookup[0][255]);
2103
2104 static uint s_next_comp[4] = { 1, 2, 0, 1 };
2105
2106 uint best_error = cUINT32_MAX, best_i = 0;
2107 int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
2108 uint i;
2109
2110 // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations
2111 // that allow that 8-bit value to be encoded with no error.
2112 for (i = 0; i < 3; i++)
2113 {
2114 const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
2115
2116 const int delta_range = 1;
2117 int delta;
2118 for (delta = -delta_range; delta <= delta_range; delta++)
2119 {
2120 const int c_plus_delta = CLAMP(pColor[i] + delta, 0, 255);
2121
2122 uint16* pTable;
2123 if (!c_plus_delta)
2124 pTable = (uint16 *)rg_etc_color8_to_etc_block_config_0_255[0];
2125 else if (c_plus_delta == 255)
2126 pTable = (uint16 *)rg_etc_color8_to_etc_block_config_0_255[1];
2127 else
2128 pTable = (uint16 *)rg_etc_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
2129
2130 do
2131 {
2132 const uint x = *pTable++;
2133 uint16* pInverse_table;
2134 uint16 p1, p2;
2135 uint trial_error;
2136
2137#ifdef RG_ETC1_BUILD_DEBUG
2138 const uint diff = x & 1;
2139 const uint inten = (x >> 1) & 7;
2140 const uint selector = (x >> 4) & 3;
2141 const uint p0 = (x >> 8) & 255;
2142 RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
2143#endif
2144
2145 pInverse_table = rg_etc1_inverse_lookup[x & 0xFF];
2146 p1 = pInverse_table[c1];
2147 p2 = pInverse_table[c2];
2148 trial_error = SQUARE((c_plus_delta - pColor[i])) + SQUARE((p1 >> 8)) + SQUARE((p2 >> 8));
2149 if (trial_error < best_error)
2150 {
2151 best_error = trial_error;
2152 best_x = x;
2153 best_packed_c1 = p1 & 0xFF;
2154 best_packed_c2 = p2 & 0xFF;
2155 best_i = i;
2156 if (!best_error)
2157 goto found_perfect_match;
2158 }
2159 } while (*pTable != 0xFFFF);
2160 }
2161 }
2162 found_perfect_match:
2163 {
2164 const uint diff = best_x & 1;
2165 const uint inten = (best_x >> 1) & 7;
2166 uint etc1_selector;
2167 uint best_packed_c0;
2168 uint selector_val;
2169
2170 block[3] = (uint8)(((inten | (inten << 3)) << 2) | (diff << 1));
2171
2172 etc1_selector = rg_etc_selector_index_to_etc1[(best_x >> 4) & 3];
2173 selector_val = (etc1_selector & 2) ? 0xFFFF : 0;
2174 memcpy(&block[4], &selector_val, 2);
2175 selector_val = (etc1_selector & 1) ? 0xFFFF : 0;
2176 memcpy(&block[6], &selector_val, 2);
2177
2178 best_packed_c0 = (best_x >> 8) & 255;
2179 if (diff)
2180 {
2181 block[best_i] = (uint8)(best_packed_c0 << 3);
2182 block[s_next_comp[best_i]] = (uint8)(best_packed_c1 << 3);
2183 block[s_next_comp[best_i+1]] = (uint8)(best_packed_c2 << 3);
2184 }
2185 else
2186 {
2187 block[best_i] = (uint8)(best_packed_c0 | (best_packed_c0 << 4));
2188 block[s_next_comp[best_i]] = (uint8)(best_packed_c1 | (best_packed_c1 << 4));
2189 block[s_next_comp[best_i+1]] = (uint8)(best_packed_c2 | (best_packed_c2 << 4));
2190 }
2191 }
2192 return best_error;
2193}
2194
2195static uint
2196rg_etc1_pack_block_solid_color_constrained(rg_etc1_optimizer_results *results,uint num_colors,
2197 const uint8* pColor, rg_etc1_pack_params *pack_params,
2198 bool use_diff, const color_quad_u8* pBase_color5_unscaled)
2199{
2200 RG_ETC1_ASSERT(rg_etc1_inverse_lookup[0][255]);
2201 static uint s_next_comp[4] = { 1, 2, 0, 1 };
2202 uint best_error = cUINT32_MAX, best_i = 0;
2203 int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
2204 uint i;
2205
2206 // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations
2207 // that allow that 8-bit value to be encoded with no error.
2208 for (i = 0; i < 3; i++)
2209 {
2210 const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
2211 const int delta_range = 1;
2212 int delta;
2213 for (delta = -delta_range; delta <= delta_range; delta++)
2214 {
2215 const int c_plus_delta = CLAMP(pColor[i] + delta, 0, 255);
2216 const uint16* pTable;
2217 if (!c_plus_delta)
2218 pTable = rg_etc_color8_to_etc_block_config_0_255[0];
2219 else if (c_plus_delta == 255)
2220 pTable = rg_etc_color8_to_etc_block_config_0_255[1];
2221 else
2222 pTable = rg_etc_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
2223
2224 do
2225 {
2226 const uint x = *pTable++;
2227 const uint diff = x & 1;
2228 if (((uint)use_diff) != diff)
2229 {
2230 if (*pTable == 0xFFFF)
2231 break;
2232 continue;
2233 }
2234
2235 if ((diff) && (pBase_color5_unscaled))
2236 {
2237 const int p0 = (x >> 8) & 255;
2238 unsigned char c1 = rg_etc1_color_quad_component_get(pBase_color5_unscaled->m_u32,
2239 i);
2240 int delta = p0 - (int)(c1);
2241 if ((delta < cETC1ColorDeltaMin) || (delta > cETC1ColorDeltaMax))
2242 {
2243 if (*pTable == 0xFFFF)
2244 break;
2245 continue;
2246 }
2247 }
2248
2249#ifdef RG_ETC1_BUILD_DEBUG
2250 {
2251 const uint inten = (x >> 1) & 7;
2252 const uint selector = (x >> 4) & 3;
2253 const uint p0 = (x >> 8) & 255;
2254 RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
2255 }
2256#endif
2257
2258 const uint16* pInverse_table = rg_etc1_inverse_lookup[x & 0xFF];
2259 uint16 p1 = pInverse_table[c1];
2260 uint16 p2 = pInverse_table[c2];
2261 uint trial_error;
2262
2263 if ((diff) && (pBase_color5_unscaled))
2264 {
2265 unsigned char c1 = rg_etc1_color_quad_component_get(pBase_color5_unscaled->m_u32,
2266 s_next_comp[i]);
2267 int delta1 = (p1 & 0xFF) - (int)(c1);
2268 unsigned char c2 = rg_etc1_color_quad_component_get(pBase_color5_unscaled->m_u32,
2269 s_next_comp[i + 1]);
2270 int delta2 = (p2 & 0xFF) - (int)(c2);
2271 if ((delta1 < cETC1ColorDeltaMin) || (delta1 > cETC1ColorDeltaMax)
2272 || (delta2 < cETC1ColorDeltaMin) || (delta2 > cETC1ColorDeltaMax))
2273 {
2274 if (*pTable == 0xFFFF)
2275 break;
2276 continue;
2277 }
2278 }
2279
2280 trial_error = SQUARE((c_plus_delta - pColor[i])) + SQUARE((p1 >> 8)) + SQUARE((p2 >> 8));
2281 if (trial_error < best_error)
2282 {
2283 best_error = trial_error;
2284 best_x = x;
2285 best_packed_c1 = p1 & 0xFF;
2286 best_packed_c2 = p2 & 0xFF;
2287 best_i = i;
2288 if (!best_error)
2289 goto found_perfect_match;
2290 }
2291 } while (*pTable != 0xFFFF);
2292 }
2293 }
2294 found_perfect_match:
2295
2296 if (best_error == cUINT32_MAX)
2297 return best_error;
2298
2299 best_error *= num_colors;
2300
2301 results->m_n = num_colors;
2302 results->m_block_color4 = !(best_x & 1);
2303 results->m_block_inten_table = (best_x >> 1) & 7;
2304 memset(results->m_pSelectors, (best_x >> 4) & 3, num_colors);
2305 {
2306 const uint best_packed_c0 = (best_x >> 8) & 255;
2307 rg_etc1_color_quad_u8_component_set(&results->m_block_color_unscaled, best_i, (uint8)best_packed_c0);
2308 rg_etc1_color_quad_u8_component_set(&results->m_block_color_unscaled, s_next_comp[best_i], (uint8)best_packed_c1);
2309 rg_etc1_color_quad_u8_component_set(&results->m_block_color_unscaled, s_next_comp[best_i+1], (uint8)best_packed_c2);
2310 results->m_error = best_error;
2311 }
2312 return best_error;
2313}
2314
2315// Function originally from RYG's public domain real-time DXT1 compressor, modified for 555.
2316static void
2317rg_etc1_dither_block_555(color_quad_u8* dest, color_quad_u8* block)
2318{
2319 int err[8],*ep1 = err,*ep2 = err+4;
2320 uint8 *quant = rg_etc_quant5_tab+8;
2321 int ch;
2322
2323 memset(dest, 0xFF, sizeof(color_quad_u8)*16);
2324
2325 // process channels seperately
2326 for(ch=0;ch<3;ch++)
2327 {
2328 uint8* bp = (uint8*)block;
2329 uint8* dp = (uint8*)dest;
2330 int y;
2331
2332 bp += ch; dp += ch;
2333
2334 memset(err,0, sizeof(err));
2335 for(y = 0; y < 4; y++)
2336 {
2337 int *tmp;
2338 // pixel 0
2339 dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)];
2340 ep1[0] = bp[ 0] - dp[ 0];
2341
2342 // pixel 1
2343 dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)];
2344 ep1[1] = bp[ 4] - dp[ 4];
2345
2346 // pixel 2
2347 dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)];
2348 ep1[2] = bp[ 8] - dp[ 8];
2349
2350 // pixel 3
2351 dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)];
2352 ep1[3] = bp[12] - dp[12];
2353
2354 // advance to next line
2355 tmp = ep1; ep1 = ep2; ep2 = tmp;
2356 bp += 16;
2357 dp += 16;
2358 }
2359 }
2360}
2361
2362unsigned int
2363rg_etc1_pack_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, rg_etc1_pack_params *pack_params)
2364{
2365 color_quad_u8* pSrc_pixels = (color_quad_u8 *)pSrc_pixels_rgba;
2366 unsigned char *dst_block = (unsigned char *)pETC1_block;
2367 unsigned int first_pixel_u32;
2368 int r;
2369 color_quad_u8 dithered_pixels[16], subblock_pixels[8];
2370 uint64 best_error = cUINT64_MAX;
2371 uint best_use_color4=false;
2372 uint best_flip=false;
2373 uint8 best_selectors[2][8];
2374 rg_etc1_optimizer optimizer;
2375 rg_etc1_optimizer_results best_results[2];
2376 rg_etc1_optimizer_results results[3];
2377 rg_etc1_optimizer_params params;
2378 uint i, flip;
2379 uint8 selectors[3][8];
2380 int dr, dg, db;
2381 uint selector0 = 0, selector1 = 0;
2382 static const int s_scan_delta_0_to_4[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 };
2383 static const int s_scan_delta_0_to_1[] = { -1, 0, 1 };
2384 static const int s_scan_delta_0[] = { 0 };
2385 first_pixel_u32= pSrc_pixels->m_u32;
2386
2387#ifdef RG_ETC1_BUILD_DEBUG
2388 // Ensure all alpha values are 0xFF.
2389 for (i = 0; i < 16; i++)
2390 {
2391 RG_ETC1_ASSERT(pSrc_pixels[i].comp.a == 255);
2392 }
2393#endif
2394 rg_etc1_optimizer_clear(&optimizer);
2395
2396 // Check for solid block.
2397 for (r = 15; r >= 1; --r)
2398 if (pSrc_pixels[r].m_u32 != first_pixel_u32)
2399 break;
2400 if (!r)
2401 return (unsigned int)(16 * rg_etc1_pack_block_solid_color(dst_block, &pSrc_pixels[0].comp.r, pack_params));
2402 if (pack_params->m_dithering)
2403 {
2404 rg_etc1_dither_block_555(dithered_pixels, pSrc_pixels);
2405 pSrc_pixels = dithered_pixels;
2406 }
2407
2408 for (i = 0; i < 2; i++)
2409 {
2410 best_results[i].m_n = 8;
2411 best_results[i].m_pSelectors = best_selectors[i];
2412 }
2413
2414 for (i = 0; i < 3; i++)
2415 {
2416 results[i].m_n = 8;
2417 results[i].m_pSelectors = selectors[i];
2418 }
2419
2420 rg_etc1_optimizer_params_clean(&params);
2421 params.base_params = pack_params;
2422 params.m_num_src_pixels = 8;
2423 params.m_pSrc_pixels = subblock_pixels;
2424
2425 for (flip = 0; flip < 2; flip++)
2426 {
2427 uint use_color4;
2428 for (use_color4 = 0; use_color4 < 2; use_color4++)
2429 {
2430 uint64 trial_error = 0;
2431
2432 uint subblock;
2433 for (subblock = 0; subblock < 2; subblock++)
2434 {
2435 if (flip)
2436 memcpy(subblock_pixels, pSrc_pixels + subblock * 8, sizeof(color_quad_u8) * 8);
2437 else
2438 {
2439 const color_quad_u8* pSrc_col = pSrc_pixels + subblock * 2;
2440 rg_etc1_color_quad_u8_copy(&subblock_pixels[0], &pSrc_col[0]);
2441 rg_etc1_color_quad_u8_copy(&subblock_pixels[1], &pSrc_col[4]);
2442 rg_etc1_color_quad_u8_copy(&subblock_pixels[2], &pSrc_col[8]);
2443 rg_etc1_color_quad_u8_copy(&subblock_pixels[3], &pSrc_col[12]);
2444 rg_etc1_color_quad_u8_copy(&subblock_pixels[4], &pSrc_col[1]);
2445 rg_etc1_color_quad_u8_copy(&subblock_pixels[5], &pSrc_col[5]);
2446 rg_etc1_color_quad_u8_copy(&subblock_pixels[6], &pSrc_col[9]);
2447 rg_etc1_color_quad_u8_copy(&subblock_pixels[7], &pSrc_col[13]);
2448 }
2449
2450 results[2].m_error = cUINT64_MAX;
2451 if ((params.base_params->m_quality >= rg_etc1_medium_quality) && ((subblock) || (use_color4)))
2452 {
2453 const uint32 subblock_pixel0_u32 = subblock_pixels[0].m_u32;
2454 for (r = 7; r >= 1; --r)
2455 if (subblock_pixels[r].m_u32 != subblock_pixel0_u32)
2456 break;
2457 if (!r)
2458 {
2459 rg_etc1_pack_block_solid_color_constrained(&results[2], 8, &subblock_pixels[0].comp.r,
2460 pack_params, !use_color4,
2461 (subblock && !use_color4) ? &results[0].m_block_color_unscaled : NULL);
2462 }
2463 }
2464
2465 params.m_use_color4 = (use_color4 != 0);
2466 params.m_constrain_against_base_color5 = false;
2467
2468 if ((!use_color4) && (subblock))
2469 {
2470 params.m_constrain_against_base_color5 = true;
2471 rg_etc1_color_quad_u8_copy(&params.m_base_color5,&results[0].m_block_color_unscaled);
2472 }
2473
2474 if (params.base_params->m_quality == rg_etc1_high_quality)
2475 {
2476 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_4);
2477 params.m_pScan_deltas = s_scan_delta_0_to_4;
2478 }
2479 else if (params.base_params->m_quality == rg_etc1_medium_quality)
2480 {
2481 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_1);
2482 params.m_pScan_deltas = s_scan_delta_0_to_1;
2483 }
2484 else
2485 {
2486 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0);
2487 params.m_pScan_deltas = s_scan_delta_0;
2488 }
2489
2490 rg_etc1_optimizer_init(&optimizer, &params, &results[subblock]);
2491 if (!rg_etc1_optimizer_compute(&optimizer))
2492 break;
2493
2494 if (params.base_params->m_quality >= rg_etc1_medium_quality)
2495 {
2496 // TODO: Fix fairly arbitrary/unrefined thresholds that control how far away to scan for potentially better solutions.
2497 const uint refinement_error_thresh0 = 3000;
2498 const uint refinement_error_thresh1 = 6000;
2499 if (results[subblock].m_error > refinement_error_thresh0)
2500 {
2501 if (params.base_params->m_quality == rg_etc1_medium_quality)
2502 {
2503 static const int s_scan_delta_2_to_3[] = { -3, -2, 2, 3 };
2504 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_2_to_3);
2505 params.m_pScan_deltas = s_scan_delta_2_to_3;
2506 }
2507 else
2508 {
2509 static const int s_scan_delta_5_to_5[] = { -5, 5 };
2510 static const int s_scan_delta_5_to_8[] = { -8, -7, -6, -5, 5, 6, 7, 8 };
2511 if (results[subblock].m_error > refinement_error_thresh1)
2512 {
2513 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_8);
2514 params.m_pScan_deltas = s_scan_delta_5_to_8;
2515 }
2516 else
2517 {
2518 params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_5);
2519 params.m_pScan_deltas = s_scan_delta_5_to_5;
2520 }
2521 }
2522
2523 if (!rg_etc1_optimizer_compute(&optimizer))
2524 break;
2525 }
2526
2527 if (results[2].m_error < results[subblock].m_error)
2528 results[subblock] = results[2];
2529 }
2530
2531 trial_error += results[subblock].m_error;
2532 if (trial_error >= best_error)
2533 break;
2534 }
2535
2536 if (subblock < 2)
2537 continue;
2538
2539 best_error = trial_error;
2540 rg_etc1_optimizer_results_duplicate(&best_results[0], &results[0]);
2541 rg_etc1_optimizer_results_duplicate(&best_results[1], &results[1]);
2542 best_flip = flip;
2543 best_use_color4 = use_color4;
2544 } // use_color4
2545 } // flip
2546
2547 dr = best_results[1].m_block_color_unscaled.comp.r - best_results[0].m_block_color_unscaled.comp.r;
2548 dg = best_results[1].m_block_color_unscaled.comp.g - best_results[0].m_block_color_unscaled.comp.g;
2549 db = best_results[1].m_block_color_unscaled.comp.b - best_results[0].m_block_color_unscaled.comp.b;
2550 RG_ETC1_ASSERT(best_use_color4 || (MIN(MIN(dr, dg), db) >= cETC1ColorDeltaMin) && (MAX(MAX(dr, dg), db) <= cETC1ColorDeltaMax));
2551
2552 if (best_use_color4)
2553 {
2554 dst_block[0] = (uint8)(best_results[1].m_block_color_unscaled.comp.r |
2555 (best_results[0].m_block_color_unscaled.comp.r << 4));
2556 dst_block[1] = (uint8)(best_results[1].m_block_color_unscaled.comp.g |
2557 (best_results[0].m_block_color_unscaled.comp.g << 4));
2558 dst_block[2] = (uint8)(best_results[1].m_block_color_unscaled.comp.b |
2559 (best_results[0].m_block_color_unscaled.comp.b << 4));
2560 }
2561 else
2562 {
2563 if (dr < 0) dr += 8; dst_block[0] = (uint8)((best_results[0].m_block_color_unscaled.comp.r << 3) | dr);
2564 if (dg < 0) dg += 8; dst_block[1] = (uint8)((best_results[0].m_block_color_unscaled.comp.g << 3) | dg);
2565 if (db < 0) db += 8; dst_block[2] = (uint8)((best_results[0].m_block_color_unscaled.comp.b << 3) | db);
2566 }
2567
2568 dst_block[3] = (uint8)((best_results[1].m_block_inten_table << 2) |
2569 (best_results[0].m_block_inten_table << 5) |
2570 ((~best_use_color4 & 1) << 1) | best_flip );
2571
2572 if (best_flip)
2573 {
2574 // flipped:
2575 // { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
2576 // { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
2577 //
2578 // { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
2579 // { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
2580 const uint8* pSelectors0 = best_results[0].m_pSelectors;
2581 const uint8* pSelectors1 = best_results[1].m_pSelectors;
2582 int x;
2583 for (x = 3; x >= 0; --x)
2584 {
2585 uint b;
2586 b = rg_etc_selector_index_to_etc1[pSelectors1[4 + x]];
2587 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2588
2589 b = rg_etc_selector_index_to_etc1[pSelectors1[x]];
2590 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2591
2592 b = rg_etc_selector_index_to_etc1[pSelectors0[4 + x]];
2593 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2594
2595 b = rg_etc_selector_index_to_etc1[pSelectors0[x]];
2596 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2597 }
2598 }
2599 else
2600 {
2601 // non-flipped:
2602 // { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
2603 // { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
2604 //
2605 // { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
2606 // { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
2607 int subblock;
2608 for (subblock = 1; subblock >= 0; --subblock)
2609 {
2610 const uint8* pSelectors = best_results[subblock].m_pSelectors + 4;
2611 uint i;
2612 for (i = 0; i < 2; i++)
2613 {
2614 uint b;
2615 b = rg_etc_selector_index_to_etc1[pSelectors[3]];
2616 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2617
2618 b = rg_etc_selector_index_to_etc1[pSelectors[2]];
2619 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2620
2621 b = rg_etc_selector_index_to_etc1[pSelectors[1]];
2622 selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
2623
2624 b = rg_etc_selector_index_to_etc1[pSelectors[0]];
2625 selector0 = (selector0 << 1) | (b & 1);selector1 = (selector1 << 1) | (b >> 1);
2626
2627 pSelectors -= 4;
2628 }
2629 }
2630 }
2631
2632 dst_block[4] = (uint8)(selector1 >> 8); dst_block[5] = (uint8)(selector1 & 0xFF);
2633 dst_block[6] = (uint8)(selector0 >> 8); dst_block[7] = (uint8)(selector0 & 0xFF);
2634 return (unsigned int)(best_error);
2635}
diff --git a/src/static_libs/rg_etc/rg_etc1.cpp b/src/static_libs/rg_etc/rg_etc1.cpp
deleted file mode 100644
index 8e28b53..0000000
--- a/src/static_libs/rg_etc/rg_etc1.cpp
+++ /dev/null
@@ -1,2446 +0,0 @@
1// File: rg_etc1.cpp - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
2// Please see ZLIB license at the end of rg_etc1.h.
3//
4// For more information Ericsson Texture Compression (ETC/ETC1), see:
5// http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
6//
7// v1.04 - 5/15/14 - Fix signed vs. unsigned subtraction problem (noticed when compiled with gcc) in pack_etc1_block_init().
8// This issue would cause an assert when this func. was called in debug. (Note this module was developed/testing with MSVC,
9// I still need to test it throughly when compiled with gcc.)
10//
11// v1.03 - 5/12/13 - Initial public release
12#include "rg_etc1.h"
13
14#include <stdlib.h>
15#include <memory.h>
16#include <assert.h>
17//#include <stdio.h>
18#include <math.h>
19
20#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
21
22#if defined(_DEBUG) || defined(DEBUG)
23#define RG_ETC1_BUILD_DEBUG
24#endif
25
26#define RG_ETC1_ASSERT assert
27
28namespace rg_etc1
29{
30 typedef unsigned char uint8;
31 typedef unsigned short uint16;
32 typedef unsigned int uint;
33 typedef unsigned int uint32;
34 typedef long long int64;
35 typedef unsigned long long uint64;
36
37 const uint32 cUINT32_MAX = 0xFFFFFFFFU;
38 const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
39
40 template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
41 template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
42 template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
43 template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
44 template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
45 template<typename T> inline T square(T value) { return value * value; }
46 template<typename T> inline void zero_object(T& obj) { memset((void*)&obj, 0, sizeof(obj)); }
47 template<typename T> inline void zero_this(T* pObj) { memset((void*)pObj, 0, sizeof(*pObj)); }
48
49 template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);
50
51#define RG_ETC1_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
52
53 enum eNoClamp { cNoClamp };
54
55 struct color_quad_u8
56 {
57 static inline int clamp(int v) { if (v & 0xFFFFFF00U) v = (~(static_cast<int>(v) >> 31)) & 0xFF; return v; }
58
59 struct component_traits { enum { cSigned = false, cFloat = false, cMin = 0U, cMax = 255U }; };
60
61 public:
62 typedef unsigned char component_t;
63 typedef int parameter_t;
64
65 enum { cNumComps = 4 };
66
67 union
68 {
69 struct
70 {
71 component_t r;
72 component_t g;
73 component_t b;
74 component_t a;
75 };
76
77 component_t c[cNumComps];
78
79 uint32 m_u32;
80 };
81
82 inline color_quad_u8()
83 {
84 }
85
86 inline color_quad_u8(const color_quad_u8& other) : m_u32(other.m_u32)
87 {
88 }
89
90 explicit inline color_quad_u8(parameter_t y, parameter_t alpha = component_traits::cMax)
91 {
92 set(y, alpha);
93 }
94
95 inline color_quad_u8(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
96 {
97 set(red, green, blue, alpha);
98 }
99
100 explicit inline color_quad_u8(eNoClamp, parameter_t y, parameter_t alpha = component_traits::cMax)
101 {
102 set_noclamp_y_alpha(y, alpha);
103 }
104
105 inline color_quad_u8(eNoClamp, parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
106 {
107 set_noclamp_rgba(red, green, blue, alpha);
108 }
109
110 inline void clear()
111 {
112 m_u32 = 0;
113 }
114
115 inline color_quad_u8& operator= (const color_quad_u8& other)
116 {
117 m_u32 = other.m_u32;
118 return *this;
119 }
120
121 inline color_quad_u8& set_rgb(const color_quad_u8& other)
122 {
123 r = other.r;
124 g = other.g;
125 b = other.b;
126 return *this;
127 }
128
129 inline color_quad_u8& operator= (parameter_t y)
130 {
131 set(y, component_traits::cMax);
132 return *this;
133 }
134
135 inline color_quad_u8& set(parameter_t y, parameter_t alpha = component_traits::cMax)
136 {
137 y = clamp(y);
138 alpha = clamp(alpha);
139 r = static_cast<component_t>(y);
140 g = static_cast<component_t>(y);
141 b = static_cast<component_t>(y);
142 a = static_cast<component_t>(alpha);
143 return *this;
144 }
145
146 inline color_quad_u8& set_noclamp_y_alpha(parameter_t y, parameter_t alpha = component_traits::cMax)
147 {
148 RG_ETC1_ASSERT( (y >= component_traits::cMin) && (y <= component_traits::cMax) );
149 RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
150
151 r = static_cast<component_t>(y);
152 g = static_cast<component_t>(y);
153 b = static_cast<component_t>(y);
154 a = static_cast<component_t>(alpha);
155 return *this;
156 }
157
158 inline color_quad_u8& set(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
159 {
160 r = static_cast<component_t>(clamp(red));
161 g = static_cast<component_t>(clamp(green));
162 b = static_cast<component_t>(clamp(blue));
163 a = static_cast<component_t>(clamp(alpha));
164 return *this;
165 }
166
167 inline color_quad_u8& set_noclamp_rgba(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha)
168 {
169 RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
170 RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
171 RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
172 RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
173
174 r = static_cast<component_t>(red);
175 g = static_cast<component_t>(green);
176 b = static_cast<component_t>(blue);
177 a = static_cast<component_t>(alpha);
178 return *this;
179 }
180
181 inline color_quad_u8& set_noclamp_rgb(parameter_t red, parameter_t green, parameter_t blue)
182 {
183 RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
184 RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
185 RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
186
187 r = static_cast<component_t>(red);
188 g = static_cast<component_t>(green);
189 b = static_cast<component_t>(blue);
190 return *this;
191 }
192
193 static inline parameter_t get_min_comp() { return component_traits::cMin; }
194 static inline parameter_t get_max_comp() { return component_traits::cMax; }
195 static inline bool get_comps_are_signed() { return component_traits::cSigned; }
196
197 inline component_t operator[] (uint i) const { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
198 inline component_t& operator[] (uint i) { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
199
200 inline color_quad_u8& set_component(uint i, parameter_t f)
201 {
202 RG_ETC1_ASSERT(i < cNumComps);
203
204 c[i] = static_cast<component_t>(clamp(f));
205
206 return *this;
207 }
208
209 inline color_quad_u8& set_grayscale(parameter_t l)
210 {
211 component_t x = static_cast<component_t>(clamp(l));
212 c[0] = x;
213 c[1] = x;
214 c[2] = x;
215 return *this;
216 }
217
218 inline color_quad_u8& clamp(const color_quad_u8& l, const color_quad_u8& h)
219 {
220 for (uint i = 0; i < cNumComps; i++)
221 c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l[i], h[i]));
222 return *this;
223 }
224
225 inline color_quad_u8& clamp(parameter_t l, parameter_t h)
226 {
227 for (uint i = 0; i < cNumComps; i++)
228 c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l, h));
229 return *this;
230 }
231
232 // Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
233 inline parameter_t get_luma() const
234 {
235 return static_cast<parameter_t>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
236 }
237
238 // Returns REC 709 luma.
239 inline parameter_t get_luma_rec709() const
240 {
241 return static_cast<parameter_t>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
242 }
243
244 inline uint squared_distance_rgb(const color_quad_u8& c) const
245 {
246 return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b);
247 }
248
249 inline uint squared_distance_rgba(const color_quad_u8& c) const
250 {
251 return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b) + rg_etc1::square(a - c.a);
252 }
253
254 inline bool rgb_equals(const color_quad_u8& rhs) const
255 {
256 return (r == rhs.r) && (g == rhs.g) && (b == rhs.b);
257 }
258
259 inline bool operator== (const color_quad_u8& rhs) const
260 {
261 return m_u32 == rhs.m_u32;
262 }
263
264 color_quad_u8& operator+= (const color_quad_u8& other)
265 {
266 for (uint i = 0; i < 4; i++)
267 c[i] = static_cast<component_t>(clamp(c[i] + other.c[i]));
268 return *this;
269 }
270
271 color_quad_u8& operator-= (const color_quad_u8& other)
272 {
273 for (uint i = 0; i < 4; i++)
274 c[i] = static_cast<component_t>(clamp(c[i] - other.c[i]));
275 return *this;
276 }
277
278 friend color_quad_u8 operator+ (const color_quad_u8& lhs, const color_quad_u8& rhs)
279 {
280 color_quad_u8 result(lhs);
281 result += rhs;
282 return result;
283 }
284
285 friend color_quad_u8 operator- (const color_quad_u8& lhs, const color_quad_u8& rhs)
286 {
287 color_quad_u8 result(lhs);
288 result -= rhs;
289 return result;
290 }
291 }; // class color_quad_u8
292
293 struct vec3F
294 {
295 float m_s[3];
296
297 inline vec3F() { }
298 inline vec3F(float s) { m_s[0] = s; m_s[1] = s; m_s[2] = s; }
299 inline vec3F(float x, float y, float z) { m_s[0] = x; m_s[1] = y; m_s[2] = z; }
300
301 inline float operator[] (uint i) const { RG_ETC1_ASSERT(i < 3); return m_s[i]; }
302
303 inline vec3F& operator += (const vec3F& other) { for (uint i = 0; i < 3; i++) m_s[i] += other.m_s[i]; return *this; }
304
305 inline vec3F& operator *= (float s) { for (uint i = 0; i < 3; i++) m_s[i] *= s; return *this; }
306 };
307
308 enum etc_constants
309 {
310 cETC1BytesPerBlock = 8U,
311
312 cETC1SelectorBits = 2U,
313 cETC1SelectorValues = 1U << cETC1SelectorBits,
314 cETC1SelectorMask = cETC1SelectorValues - 1U,
315
316 cETC1BlockShift = 2U,
317 cETC1BlockSize = 1U << cETC1BlockShift,
318
319 cETC1LSBSelectorIndicesBitOffset = 0,
320 cETC1MSBSelectorIndicesBitOffset = 16,
321
322 cETC1FlipBitOffset = 32,
323 cETC1DiffBitOffset = 33,
324
325 cETC1IntenModifierNumBits = 3,
326 cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
327 cETC1RightIntenModifierTableBitOffset = 34,
328 cETC1LeftIntenModifierTableBitOffset = 37,
329
330 // Base+Delta encoding (5 bit bases, 3 bit delta)
331 cETC1BaseColorCompNumBits = 5,
332 cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
333
334 cETC1DeltaColorCompNumBits = 3,
335 cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
336 cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
337
338 cETC1BaseColor5RBitOffset = 59,
339 cETC1BaseColor5GBitOffset = 51,
340 cETC1BaseColor5BBitOffset = 43,
341
342 cETC1DeltaColor3RBitOffset = 56,
343 cETC1DeltaColor3GBitOffset = 48,
344 cETC1DeltaColor3BBitOffset = 40,
345
346 // Absolute (non-delta) encoding (two 4-bit per component bases)
347 cETC1AbsColorCompNumBits = 4,
348 cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
349
350 cETC1AbsColor4R1BitOffset = 60,
351 cETC1AbsColor4G1BitOffset = 52,
352 cETC1AbsColor4B1BitOffset = 44,
353
354 cETC1AbsColor4R2BitOffset = 56,
355 cETC1AbsColor4G2BitOffset = 48,
356 cETC1AbsColor4B2BitOffset = 40,
357
358 cETC1ColorDeltaMin = -4,
359 cETC1ColorDeltaMax = 3,
360
361 // Delta3:
362 // 0 1 2 3 4 5 6 7
363 // 000 001 010 011 100 101 110 111
364 // 0 1 2 3 -4 -3 -2 -1
365 };
366
367 static uint8 g_quant5_tab[256+16];
368
369 static const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] =
370 {
371 { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 },
372 { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 }
373 };
374
375 static const uint8 g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
376 static const uint8 g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
377
378 // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte.
379 static uint16 g_etc1_inverse_lookup[2*8*4][256]; // [diff/inten_table/selector][desired_color]
380
381 // g_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color.
382 // To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8)
383 static const uint16 g_color8_to_etc_block_config_0_255[2][33] =
384 {
385 { 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008, 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E,
386 0x0001, 0x0011, 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B, 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF },
387 { 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38, 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E,
388 0x1E31, 0x1F21, 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B, 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF },
389 };
390
391 // Really only [254][11].
392 static const uint16 g_color8_to_etc_block_config_1_to_254[254][12] =
393 {
394 { 0x021C, 0x0D0D, 0xFFFF }, { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF }, { 0x0113, 0x0217, 0xFFFF }, { 0x0116, 0x031E,
395 0x0B0E, 0x0405, 0xFFFF }, { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF }, { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF }, {
396 0x0303, 0x0215, 0x0607, 0xFFFF }, { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF }, { 0x0100, 0x0024, 0x0306,
397 0x0025, 0x041B, 0x0E0D, 0xFFFF }, { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF }, { 0x0213, 0x0317, 0xFFFF }, { 0x0112,
398 0x0505, 0xFFFF }, { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF }, { 0x0211, 0x0909, 0xFFFF }, { 0x0110, 0x0315, 0x0707,
399 0x0419, 0x180F, 0xFFFF }, { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF }, { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B,
400 0x0F0D, 0xFFFF }, { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF }, { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF }, { 0x0605,
401 0x0417, 0xFFFF }, { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF }, { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF
402 }, { 0x0519, 0x190F, 0xFFFF }, { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF }, { 0x0130, 0x0214,
403 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF }, { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF }, { 0x031A,
404 0x0D0B, 0x091F, 0xFFFF }, { 0x0413, 0x0705, 0x0517, 0xFFFF }, { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF }, {
405 0x0126, 0x080C, 0x0B09, 0xFFFF }, { 0x0411, 0x0619, 0x1A0F, 0xFFFF }, { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B,
406 0xFFFF }, { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF }, { 0x0132, 0x0302, 0x0229, 0x110D,
407 0xFFFF }, { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF }, { 0x0220, 0x0513, 0x0617, 0xFFFF }, { 0x0135, 0x0805,
408 0x0327, 0xFFFF }, { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF }, { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F,
409 0xFFFF }, { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF }, { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF }, {
410 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF }, { 0x0300, 0x0224, 0x0506, 0x0521,
411 0x0F0B, 0x0B1F, 0xFFFF }, { 0x041A, 0x0613, 0x0717, 0xFFFF }, { 0x0235, 0x0905, 0xFFFF }, { 0x0312, 0x0134, 0x0523,
412 0x0427, 0xFFFF }, { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF }, { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F,
413 0xFFFF }, { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF }, { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B,
414 0x130D, 0xFFFF }, { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF }, { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF }, {
415 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF }, { 0x0623, 0x0527, 0xFFFF }, { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F,
416 0xFFFF }, { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF }, { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D,
417 0xFFFF }, { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF }, { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529,
418 0x140D, 0xFFFF }, { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF }, { 0x051A, 0x0813, 0x0B05, 0x0917,
419 0xFFFF }, { 0x0723, 0x0435, 0x0627, 0xFFFF }, { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF }, { 0x0326, 0x0A0C, 0x012E,
420 0x0811, 0x0A19, 0x1E0F, 0xFFFF }, { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF }, { 0x0410, 0x0901, 0x0633, 0x0725,
421 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF }, { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF }, { 0x0332, 0x0502, 0x0821, 0x0139,
422 0x120B, 0x0E1F, 0xFFFF }, { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF }, { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF }, {
423 0x0823, 0x032F, 0xFFFF }, { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF }, { 0x0422, 0x0604, 0x090A,
424 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF }, { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF }, { 0x032A, 0x0825, 0x0437,
425 0x0729, 0x0C1B, 0x160D, 0xFFFF }, { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF }, { 0x0500,
426 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF }, { 0x061A, 0x0635, 0x0D05, 0xFFFF }, { 0x0923, 0x0827, 0xFFFF }, {
427 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF }, { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19,
428 0x072B, 0xFFFF }, { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF }, { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D,
429 0xFFFF }, { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF }, { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF }, {
430 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF }, { 0x0520, 0x0A23, 0x0927, 0xFFFF }, { 0x0B11, 0x1209, 0x013B, 0x052F,
431 0xFFFF }, { 0x0616, 0x081E, 0x0D19, 0xFFFF }, { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D,
432 0x0F1D, 0xFFFF }, { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF }, { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF }, {
433 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF }, { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05,
434 0x0D17, 0xFFFF }, { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF }, { 0x1309, 0x023B, 0x062F, 0xFFFF }, { 0x0612, 0x0434,
435 0x013A, 0x0C11, 0x0E19, 0xFFFF }, { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF }, { 0x0D01,
436 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF }, { 0x0610, 0x0A29, 0x190D, 0xFFFF }, { 0x0718, 0x042C, 0x0C21,
437 0x0539, 0x160B, 0x121F, 0xFFFF }, { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF }, { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27,
438 0xFFFF }, { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF }, { 0x0D11, 0x0F19, 0x1409, 0xFFFF }, { 0x0716, 0x003C, 0x091E,
439 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF }, { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D,
440 0xFFFF }, { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF }, { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF }, {
441 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF }, { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF }, {
442 0x081A, 0x0D23, 0x0C27, 0xFFFF }, { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF }, { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307,
443 0x1019, 0x0B2B, 0x013D, 0xFFFF }, { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF }, { 0x0C33,
444 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF }, { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF }, { 0x0818, 0x052C, 0x0F13, 0x180B,
445 0x141F, 0xFFFF }, { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF }, { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF }, {
446 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF }, { 0x1119, 0x023D, 0xFFFF }, { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103,
447 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF }, { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B,
448 0xFFFF }, { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF }, { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF }, { 0x0730, 0x0814, 0x0536,
449 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF }, { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF }, { 0x091A,
450 0x1709, 0x063B, 0x0A2F, 0xFFFF }, { 0x1011, 0x1219, 0x033D, 0xFFFF }, { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115,
451 0x1507, 0x0D2B, 0xFFFF }, { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF }, {
452 0x0E29, 0x1D0D, 0xFFFF }, { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF }, { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF
453 }, { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF }, { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF }, { 0x0820,
454 0x1111, 0x1319, 0x1809, 0xFFFF }, { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF }, { 0x0916, 0x023C, 0x0B1E, 0x1031,
455 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF }, { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF }, {
456 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF }, { 0x072A, 0x1213, 0x1317, 0xFFFF }, { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35,
457 0x1505, 0xFFFF }, { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF }, { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F,
458 0xFFFF }, { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF }, { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D,
459 0x161D, 0xFFFF }, { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF }, { 0x1221, 0x0B39, 0x1029,
460 0xFFFF }, { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF }, { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF }, { 0x0832,
461 0x0A02, 0x1223, 0x1127, 0xFFFF }, { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF }, { 0x0920, 0x1519, 0x063D,
462 0xFFFF }, { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF }, { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133,
463 0x1225, 0x0E37, 0x161B, 0xFFFF }, { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF }, { 0x0C39, 0x1D0B, 0x191F, 0xFFFF
464 }, { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF }, { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF }, {
465 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF }, { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF }, { 0x1331,
466 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF }, { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D,
467 0x181D, 0xFFFF }, { 0x0926, 0x072E, 0x1229, 0xFFFF }, { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF }, { 0x0A10, 0x1513,
468 0x1617, 0xFFFF }, { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF }, { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF
469 }, { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF }, { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF }, {
470 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF }, { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF }, {
471 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF }, { 0x1613, 0x1717, 0xFFFF }, { 0x092A, 0x1235, 0x1905,
472 0xFFFF }, { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF }, { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09,
473 0x0C3B, 0x102F, 0xFFFF }, { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF }, { 0x1531, 0x1701, 0x1803, 0x122D,
474 0x1A1D, 0xFFFF }, { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF }, { 0x0A26, 0x003E, 0x082E, 0x1621,
475 0x0F39, 0x1429, 0x003F, 0xFFFF }, { 0x1713, 0x1C1F, 0xFFFF }, { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF }, { 0x0C18,
476 0x092C, 0x1623, 0x1527, 0xFFFF }, { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF }, { 0x0A28, 0x0D1C, 0x1919,
477 0x0A3D, 0xFFFF }, { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF }, { 0x1801, 0x1533, 0x1625,
478 0x1237, 0x1A1B, 0xFFFF }, { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF }, { 0x0B22, 0x0D04, 0x1039, 0x1D1F,
479 0xFFFF }, { 0x1813, 0x1B05, 0x1917, 0xFFFF }, { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF }, { 0x0B30, 0x0C14, 0x0936,
480 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF }, { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF }, { 0x0D1A,
481 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF }, { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF }, {
482 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF }, { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF }, { 0x1913,
483 0x1A17, 0xFFFF }, { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF }, { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF }, {
484 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF }, { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF }, { 0x0C20,
485 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF }, { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF }, { 0x0D16, 0x063C,
486 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF }, { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF }, { 0x1635, 0x1D05, 0xFFFF }, {
487 0x0B2A, 0x1923, 0x1827, 0xFFFF }, { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF }, { 0x0D00, 0x0C24, 0x0F06,
488 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF }, { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF }, {
489 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF }, { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF }, { 0x0C26,
490 0x023E, 0x0A2E, 0x1B13, 0xFFFF }, { 0x1735, 0x1E05, 0x1C17, 0xFFFF }, { 0x0D10, 0x1A23, 0x1927, 0xFFFF }, { 0x0E18,
491 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF }, { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF }, { 0x0C28, 0x0F1C, 0x1A31, 0x1D03,
492 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF }, { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF }, { 0x1B21, 0x1929,
493 0x053F, 0xFFFF }, { 0x0E16, 0x073C, 0x1439, 0xFFFF }, { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF }, { 0x1B23,
494 0x1835, 0x1A27, 0xFFFF }, { 0x0C2A, 0x123B, 0x162F, 0xFFFF }, { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF
495 }, { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF }, { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B,
496 0x182D, 0xFFFF }, { 0x1A29, 0x063F, 0xFFFF }, { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF }, { 0x0D26, 0x033E,
497 0x0B2E, 0x1D13, 0x1E17, 0xFFFF }, { 0x1935, 0x1B27, 0xFFFF }, { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF }, { 0x0F18,
498 0x0C2C, 0x1D11, 0x1F19, 0xFFFF }, { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF }, { 0x0D28, 0x1C31, 0x1E01,
499 0x1B33, 0x192D, 0xFFFF }, { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF }, { 0x1D21, 0x1639, 0xFFFF }, { 0x0F16,
500 0x083C, 0x1E13, 0x1F17, 0xFFFF }, { 0x0E22, 0x1A35, 0xFFFF }, { 0x1D23, 0x1C27, 0xFFFF }, { 0x0D2A, 0x1E11, 0x143B,
501 0x182F, 0xFFFF }, { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF }, { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01,
502 0x1A2D, 0xFFFF }, { 0x1C33, 0x1D25, 0x1937, 0xFFFF }, { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF }, { 0x0F12, 0x0D34,
503 0x0A3A, 0x1F13, 0xFFFF }, { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF }, { 0x1E23, 0x1D27, 0xFFFF }, { 0x0F10, 0x1F11,
504 0x153B, 0x192F, 0xFFFF }, { 0x0D2C, 0x123D, 0xFFFF },
505 };
506
507 struct etc1_block
508 {
509 // big endian uint64:
510 // bit ofs: 56 48 40 32 24 16 8 0
511 // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
512 union
513 {
514 uint64 m_uint64;
515 uint8 m_bytes[8];
516 };
517
518 uint8 m_low_color[2];
519 uint8 m_high_color[2];
520
521 enum { cNumSelectorBytes = 4 };
522 uint8 m_selectors[cNumSelectorBytes];
523
524 inline void clear()
525 {
526 zero_this(this);
527 }
528
529 inline uint get_byte_bits(uint ofs, uint num) const
530 {
531 RG_ETC1_ASSERT((ofs + num) <= 64U);
532 RG_ETC1_ASSERT(num && (num <= 8U));
533 RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
534 const uint byte_ofs = 7 - (ofs >> 3);
535 const uint byte_bit_ofs = ofs & 7;
536 return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
537 }
538
539 inline void set_byte_bits(uint ofs, uint num, uint bits)
540 {
541 RG_ETC1_ASSERT((ofs + num) <= 64U);
542 RG_ETC1_ASSERT(num && (num < 32U));
543 RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
544 RG_ETC1_ASSERT(bits < (1U << num));
545 const uint byte_ofs = 7 - (ofs >> 3);
546 const uint byte_bit_ofs = ofs & 7;
547 const uint mask = (1 << num) - 1;
548 m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
549 m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
550 }
551
552 // false = left/right subblocks
553 // true = upper/lower subblocks
554 inline bool get_flip_bit() const
555 {
556 return (m_bytes[3] & 1) != 0;
557 }
558
559 inline void set_flip_bit(bool flip)
560 {
561 m_bytes[3] &= ~1;
562 m_bytes[3] |= static_cast<uint8>(flip);
563 }
564
565 inline bool get_diff_bit() const
566 {
567 return (m_bytes[3] & 2) != 0;
568 }
569
570 inline void set_diff_bit(bool diff)
571 {
572 m_bytes[3] &= ~2;
573 m_bytes[3] |= (static_cast<uint>(diff) << 1);
574 }
575
576 // Returns intensity modifier table (0-7) used by subblock subblock_id.
577 // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
578 inline uint get_inten_table(uint subblock_id) const
579 {
580 RG_ETC1_ASSERT(subblock_id < 2);
581 const uint ofs = subblock_id ? 2 : 5;
582 return (m_bytes[3] >> ofs) & 7;
583 }
584
585 // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
586 inline void set_inten_table(uint subblock_id, uint t)
587 {
588 RG_ETC1_ASSERT(subblock_id < 2);
589 RG_ETC1_ASSERT(t < 8);
590 const uint ofs = subblock_id ? 2 : 5;
591 m_bytes[3] &= ~(7 << ofs);
592 m_bytes[3] |= (t << ofs);
593 }
594
595 // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
596 inline uint get_selector(uint x, uint y) const
597 {
598 RG_ETC1_ASSERT((x | y) < 4);
599
600 const uint bit_index = x * 4 + y;
601 const uint byte_bit_ofs = bit_index & 7;
602 const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
603 const uint lsb = (p[0] >> byte_bit_ofs) & 1;
604 const uint msb = (p[-2] >> byte_bit_ofs) & 1;
605 const uint val = lsb | (msb << 1);
606
607 return g_etc1_to_selector_index[val];
608 }
609
610 // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
611 inline void set_selector(uint x, uint y, uint val)
612 {
613 RG_ETC1_ASSERT((x | y | val) < 4);
614 const uint bit_index = x * 4 + y;
615
616 uint8 *p = &m_bytes[7 - (bit_index >> 3)];
617
618 const uint byte_bit_ofs = bit_index & 7;
619 const uint mask = 1 << byte_bit_ofs;
620
621 const uint etc1_val = g_selector_index_to_etc1[val];
622
623 const uint lsb = etc1_val & 1;
624 const uint msb = etc1_val >> 1;
625
626 p[0] &= ~mask;
627 p[0] |= (lsb << byte_bit_ofs);
628
629 p[-2] &= ~mask;
630 p[-2] |= (msb << byte_bit_ofs);
631 }
632
633 inline void set_base4_color(uint idx, uint16 c)
634 {
635 if (idx)
636 {
637 set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
638 set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
639 set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
640 }
641 else
642 {
643 set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
644 set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
645 set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
646 }
647 }
648
649 inline uint16 get_base4_color(uint idx) const
650 {
651 uint r, g, b;
652 if (idx)
653 {
654 r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
655 g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
656 b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
657 }
658 else
659 {
660 r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
661 g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
662 b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
663 }
664 return static_cast<uint16>(b | (g << 4U) | (r << 8U));
665 }
666
667 inline void set_base5_color(uint16 c)
668 {
669 set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
670 set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
671 set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
672 }
673
674 inline uint16 get_base5_color() const
675 {
676 const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
677 const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
678 const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
679 return static_cast<uint16>(b | (g << 5U) | (r << 10U));
680 }
681
682 void set_delta3_color(uint16 c)
683 {
684 set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
685 set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
686 set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
687 }
688
689 inline uint16 get_delta3_color() const
690 {
691 const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
692 const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
693 const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
694 return static_cast<uint16>(b | (g << 3U) | (r << 6U));
695 }
696
697 // Base color 5
698 static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
699 static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
700
701 static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
702 static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
703
704 static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
705 static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
706
707 // Delta color 3
708 // Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
709 static uint16 pack_delta3(int r, int g, int b);
710
711 // Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
712 static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
713
714 // Abs color 4
715 static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
716 static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
717
718 static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
719 static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
720
721 // subblock colors
722 static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
723 static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
724 static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
725
726 static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4)
727 {
728 if (color4)
729 {
730 dst.r = src.r | (src.r << 4);
731 dst.g = src.g | (src.g << 4);
732 dst.b = src.b | (src.b << 4);
733 }
734 else
735 {
736 dst.r = (src.r >> 2) | (src.r << 3);
737 dst.g = (src.g >> 2) | (src.g << 3);
738 dst.b = (src.b >> 2) | (src.b << 3);
739 }
740 dst.a = src.a;
741 }
742 };
743
744 // Returns pointer to sorted array.
745 template<typename T, typename Q>
746 T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices)
747 {
748 RG_ETC1_ASSERT((key_ofs >= 0) && (key_ofs < sizeof(T)));
749 RG_ETC1_ASSERT((key_size >= 1) && (key_size <= 4));
750
751 if (init_indices)
752 {
753 T* p = pIndices0;
754 T* q = pIndices0 + (num_indices >> 1) * 2;
755 uint i;
756 for (i = 0; p != q; p += 2, i += 2)
757 {
758 p[0] = static_cast<T>(i);
759 p[1] = static_cast<T>(i + 1);
760 }
761
762 if (num_indices & 1)
763 *p = static_cast<T>(i);
764 }
765
766 uint hist[256 * 4];
767
768 memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
769
770#define RG_ETC1_GET_KEY(p) (*(const uint*)((const uint8*)(pKeys + *(p)) + key_ofs))
771#define RG_ETC1_GET_KEY_FROM_INDEX(i) (*(const uint*)((const uint8*)(pKeys + (i)) + key_ofs))
772
773 if (key_size == 4)
774 {
775 T* p = pIndices0;
776 T* q = pIndices0 + num_indices;
777 for ( ; p != q; p++)
778 {
779 const uint key = RG_ETC1_GET_KEY(p);
780
781 hist[ key & 0xFF]++;
782 hist[256 + ((key >> 8) & 0xFF)]++;
783 hist[512 + ((key >> 16) & 0xFF)]++;
784 hist[768 + ((key >> 24) & 0xFF)]++;
785 }
786 }
787 else if (key_size == 3)
788 {
789 T* p = pIndices0;
790 T* q = pIndices0 + num_indices;
791 for ( ; p != q; p++)
792 {
793 const uint key = RG_ETC1_GET_KEY(p);
794
795 hist[ key & 0xFF]++;
796 hist[256 + ((key >> 8) & 0xFF)]++;
797 hist[512 + ((key >> 16) & 0xFF)]++;
798 }
799 }
800 else if (key_size == 2)
801 {
802 T* p = pIndices0;
803 T* q = pIndices0 + (num_indices >> 1) * 2;
804
805 for ( ; p != q; p += 2)
806 {
807 const uint key0 = RG_ETC1_GET_KEY(p);
808 const uint key1 = RG_ETC1_GET_KEY(p+1);
809
810 hist[ key0 & 0xFF]++;
811 hist[256 + ((key0 >> 8) & 0xFF)]++;
812
813 hist[ key1 & 0xFF]++;
814 hist[256 + ((key1 >> 8) & 0xFF)]++;
815 }
816
817 if (num_indices & 1)
818 {
819 const uint key = RG_ETC1_GET_KEY(p);
820
821 hist[ key & 0xFF]++;
822 hist[256 + ((key >> 8) & 0xFF)]++;
823 }
824 }
825 else
826 {
827 RG_ETC1_ASSERT(key_size == 1);
828 if (key_size != 1)
829 return NULL;
830
831 T* p = pIndices0;
832 T* q = pIndices0 + (num_indices >> 1) * 2;
833
834 for ( ; p != q; p += 2)
835 {
836 const uint key0 = RG_ETC1_GET_KEY(p);
837 const uint key1 = RG_ETC1_GET_KEY(p+1);
838
839 hist[key0 & 0xFF]++;
840 hist[key1 & 0xFF]++;
841 }
842
843 if (num_indices & 1)
844 {
845 const uint key = RG_ETC1_GET_KEY(p);
846
847 hist[key & 0xFF]++;
848 }
849 }
850
851 T* pCur = pIndices0;
852 T* pNew = pIndices1;
853
854 for (uint pass = 0; pass < key_size; pass++)
855 {
856 const uint* pHist = &hist[pass << 8];
857
858 uint offsets[256];
859
860 uint cur_ofs = 0;
861 for (uint i = 0; i < 256; i += 2)
862 {
863 offsets[i] = cur_ofs;
864 cur_ofs += pHist[i];
865
866 offsets[i+1] = cur_ofs;
867 cur_ofs += pHist[i+1];
868 }
869
870 const uint pass_shift = pass << 3;
871
872 T* p = pCur;
873 T* q = pCur + (num_indices >> 1) * 2;
874
875 for ( ; p != q; p += 2)
876 {
877 uint index0 = p[0];
878 uint index1 = p[1];
879
880 uint c0 = (RG_ETC1_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF;
881 uint c1 = (RG_ETC1_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF;
882
883 if (c0 == c1)
884 {
885 uint dst_offset0 = offsets[c0];
886
887 offsets[c0] = dst_offset0 + 2;
888
889 pNew[dst_offset0] = static_cast<T>(index0);
890 pNew[dst_offset0 + 1] = static_cast<T>(index1);
891 }
892 else
893 {
894 uint dst_offset0 = offsets[c0]++;
895 uint dst_offset1 = offsets[c1]++;
896
897 pNew[dst_offset0] = static_cast<T>(index0);
898 pNew[dst_offset1] = static_cast<T>(index1);
899 }
900 }
901
902 if (num_indices & 1)
903 {
904 uint index = *p;
905 uint c = (RG_ETC1_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF;
906
907 uint dst_offset = offsets[c];
908 offsets[c] = dst_offset + 1;
909
910 pNew[dst_offset] = static_cast<T>(index);
911 }
912
913 T* t = pCur;
914 pCur = pNew;
915 pNew = t;
916 }
917
918 return pCur;
919 }
920
921#undef RG_ETC1_GET_KEY
922#undef RG_ETC1_GET_KEY_FROM_INDEX
923
924 uint16 etc1_block::pack_color5(const color_quad_u8& color, bool scaled, uint bias)
925 {
926 return pack_color5(color.r, color.g, color.b, scaled, bias);
927 }
928
929 uint16 etc1_block::pack_color5(uint r, uint g, uint b, bool scaled, uint bias)
930 {
931 if (scaled)
932 {
933 r = (r * 31U + bias) / 255U;
934 g = (g * 31U + bias) / 255U;
935 b = (b * 31U + bias) / 255U;
936 }
937
938 r = rg_etc1::minimum(r, 31U);
939 g = rg_etc1::minimum(g, 31U);
940 b = rg_etc1::minimum(b, 31U);
941
942 return static_cast<uint16>(b | (g << 5U) | (r << 10U));
943 }
944
945 color_quad_u8 etc1_block::unpack_color5(uint16 packed_color5, bool scaled, uint alpha)
946 {
947 uint b = packed_color5 & 31U;
948 uint g = (packed_color5 >> 5U) & 31U;
949 uint r = (packed_color5 >> 10U) & 31U;
950
951 if (scaled)
952 {
953 b = (b << 3U) | (b >> 2U);
954 g = (g << 3U) | (g >> 2U);
955 r = (r << 3U) | (r >> 2U);
956 }
957
958 return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U));
959 }
960
961 void etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, bool scaled)
962 {
963 color_quad_u8 c(unpack_color5(packed_color5, scaled, 0));
964 r = c.r;
965 g = c.g;
966 b = c.b;
967 }
968
969 bool etc1_block::unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
970 {
971 int dc_r, dc_g, dc_b;
972 unpack_delta3(dc_r, dc_g, dc_b, packed_delta3);
973
974 int b = (packed_color5 & 31U) + dc_b;
975 int g = ((packed_color5 >> 5U) & 31U) + dc_g;
976 int r = ((packed_color5 >> 10U) & 31U) + dc_r;
977
978 bool success = true;
979 if (static_cast<uint>(r | g | b) > 31U)
980 {
981 success = false;
982 r = rg_etc1::clamp<int>(r, 0, 31);
983 g = rg_etc1::clamp<int>(g, 0, 31);
984 b = rg_etc1::clamp<int>(b, 0, 31);
985 }
986
987 if (scaled)
988 {
989 b = (b << 3U) | (b >> 2U);
990 g = (g << 3U) | (g >> 2U);
991 r = (r << 3U) | (r >> 2U);
992 }
993
994 result.set_noclamp_rgba(r, g, b, rg_etc1::minimum(alpha, 255U));
995 return success;
996 }
997
998 bool etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
999 {
1000 color_quad_u8 result;
1001 const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha);
1002 r = result.r;
1003 g = result.g;
1004 b = result.b;
1005 return success;
1006 }
1007
1008 uint16 etc1_block::pack_delta3(int r, int g, int b)
1009 {
1010 RG_ETC1_ASSERT((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
1011 RG_ETC1_ASSERT((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
1012 RG_ETC1_ASSERT((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
1013 if (r < 0) r += 8;
1014 if (g < 0) g += 8;
1015 if (b < 0) b += 8;
1016 return static_cast<uint16>(b | (g << 3) | (r << 6));
1017 }
1018
1019 void etc1_block::unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3)
1020 {
1021 r = (packed_delta3 >> 6) & 7;
1022 g = (packed_delta3 >> 3) & 7;
1023 b = packed_delta3 & 7;
1024 if (r >= 4) r -= 8;
1025 if (g >= 4) g -= 8;
1026 if (b >= 4) b -= 8;
1027 }
1028
102