Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/basis_universal/encoder/basisu_etc.h
9904 views
1
// basis_etc.h
2
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
// http://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
#pragma once
16
#include "../transcoder/basisu.h"
17
#include "basisu_enc.h"
18
19
namespace basisu
20
{
21
enum etc_constants
22
{
23
cETC1BytesPerBlock = 8U,
24
25
cETC1SelectorBits = 2U,
26
cETC1SelectorValues = 1U << cETC1SelectorBits,
27
cETC1SelectorMask = cETC1SelectorValues - 1U,
28
29
cETC1BlockShift = 2U,
30
cETC1BlockSize = 1U << cETC1BlockShift,
31
32
cETC1LSBSelectorIndicesBitOffset = 0,
33
cETC1MSBSelectorIndicesBitOffset = 16,
34
35
cETC1FlipBitOffset = 32,
36
cETC1DiffBitOffset = 33,
37
38
cETC1IntenModifierNumBits = 3,
39
cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
40
cETC1RightIntenModifierTableBitOffset = 34,
41
cETC1LeftIntenModifierTableBitOffset = 37,
42
43
// Base+Delta encoding (5 bit bases, 3 bit delta)
44
cETC1BaseColorCompNumBits = 5,
45
cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
46
47
cETC1DeltaColorCompNumBits = 3,
48
cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
49
cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
50
51
cETC1BaseColor5RBitOffset = 59,
52
cETC1BaseColor5GBitOffset = 51,
53
cETC1BaseColor5BBitOffset = 43,
54
55
cETC1DeltaColor3RBitOffset = 56,
56
cETC1DeltaColor3GBitOffset = 48,
57
cETC1DeltaColor3BBitOffset = 40,
58
59
// Absolute (non-delta) encoding (two 4-bit per component bases)
60
cETC1AbsColorCompNumBits = 4,
61
cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
62
63
cETC1AbsColor4R1BitOffset = 60,
64
cETC1AbsColor4G1BitOffset = 52,
65
cETC1AbsColor4B1BitOffset = 44,
66
67
cETC1AbsColor4R2BitOffset = 56,
68
cETC1AbsColor4G2BitOffset = 48,
69
cETC1AbsColor4B2BitOffset = 40,
70
71
cETC1ColorDeltaMin = -4,
72
cETC1ColorDeltaMax = 3,
73
74
// Delta3:
75
// 0 1 2 3 4 5 6 7
76
// 000 001 010 011 100 101 110 111
77
// 0 1 2 3 -4 -3 -2 -1
78
};
79
80
extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues];
81
extern const uint8_t g_etc1_to_selector_index[cETC1SelectorValues];
82
extern const uint8_t g_selector_index_to_etc1[cETC1SelectorValues];
83
84
struct etc_coord2
85
{
86
uint8_t m_x, m_y;
87
};
88
extern const etc_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
89
extern const uint32_t g_etc1_pixel_indices[2][2][8]; // [flipped][subblock][subblock_pixel]
90
91
struct etc_block
92
{
93
// big endian uint64:
94
// bit ofs: 56 48 40 32 24 16 8 0
95
// byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
96
union
97
{
98
uint64_t m_uint64;
99
100
uint8_t m_bytes[8];
101
};
102
103
inline void clear()
104
{
105
assert(sizeof(*this) == 8);
106
clear_obj(*this);
107
}
108
109
inline uint64_t get_all_bits() const
110
{
111
return read_be64(&m_uint64);
112
}
113
114
inline uint32_t get_general_bits(uint32_t ofs, uint32_t num) const
115
{
116
assert((ofs + num) <= 64U);
117
assert(num && (num < 32U));
118
return (uint32_t)(read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
119
}
120
121
inline void set_general_bits(uint32_t ofs, uint32_t num, uint32_t bits)
122
{
123
assert((ofs + num) <= 64U);
124
assert(num && (num < 32U));
125
126
uint64_t x = read_be64(&m_uint64);
127
uint64_t msk = ((1ULL << static_cast<uint64_t>(num)) - 1ULL) << static_cast<uint64_t>(ofs);
128
x &= ~msk;
129
x |= (static_cast<uint64_t>(bits) << static_cast<uint64_t>(ofs));
130
write_be64(&m_uint64, x);
131
}
132
133
inline uint32_t get_byte_bits(uint32_t ofs, uint32_t num) const
134
{
135
assert((ofs + num) <= 64U);
136
assert(num && (num <= 8U));
137
assert((ofs >> 3) == ((ofs + num - 1) >> 3));
138
const uint32_t byte_ofs = 7 - (ofs >> 3);
139
const uint32_t byte_bit_ofs = ofs & 7;
140
return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
141
}
142
143
inline void set_byte_bits(uint32_t ofs, uint32_t num, uint32_t bits)
144
{
145
assert((ofs + num) <= 64U);
146
assert(num && (num < 32U));
147
assert((ofs >> 3) == ((ofs + num - 1) >> 3));
148
assert(bits < (1U << num));
149
const uint32_t byte_ofs = 7 - (ofs >> 3);
150
const uint32_t byte_bit_ofs = ofs & 7;
151
const uint32_t mask = (1 << num) - 1;
152
m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
153
m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
154
}
155
156
// false = left/right subblocks
157
// true = upper/lower subblocks
158
inline bool get_flip_bit() const
159
{
160
return (m_bytes[3] & 1) != 0;
161
}
162
163
inline void set_flip_bit(bool flip)
164
{
165
m_bytes[3] &= ~1;
166
m_bytes[3] |= static_cast<uint8_t>(flip);
167
}
168
169
inline bool get_diff_bit() const
170
{
171
return (m_bytes[3] & 2) != 0;
172
}
173
174
inline void set_diff_bit(bool diff)
175
{
176
m_bytes[3] &= ~2;
177
m_bytes[3] |= (static_cast<uint32_t>(diff) << 1);
178
}
179
180
// Returns intensity modifier table (0-7) used by subblock subblock_id.
181
// subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
182
inline uint32_t get_inten_table(uint32_t subblock_id) const
183
{
184
assert(subblock_id < 2);
185
const uint32_t ofs = subblock_id ? 2 : 5;
186
return (m_bytes[3] >> ofs) & 7;
187
}
188
189
// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
190
inline void set_inten_table(uint32_t subblock_id, uint32_t t)
191
{
192
assert(subblock_id < 2);
193
assert(t < 8);
194
const uint32_t ofs = subblock_id ? 2 : 5;
195
m_bytes[3] &= ~(7 << ofs);
196
m_bytes[3] |= (t << ofs);
197
}
198
199
inline void set_inten_tables_etc1s(uint32_t t)
200
{
201
set_inten_table(0, t);
202
set_inten_table(1, t);
203
}
204
205
inline bool is_etc1s() const
206
{
207
if (get_inten_table(0) != get_inten_table(1))
208
return false;
209
210
if (get_diff_bit())
211
{
212
if (get_delta3_color() != 0)
213
return false;
214
}
215
else
216
{
217
if (get_base4_color(0) != get_base4_color(1))
218
return false;
219
}
220
221
return true;
222
}
223
224
// Returned encoded selector value ranges from 0-3 (this is NOT a direct index into g_etc1_inten_tables, see get_selector())
225
inline uint32_t get_raw_selector(uint32_t x, uint32_t y) const
226
{
227
assert((x | y) < 4);
228
229
const uint32_t bit_index = x * 4 + y;
230
const uint32_t byte_bit_ofs = bit_index & 7;
231
const uint8_t *p = &m_bytes[7 - (bit_index >> 3)];
232
const uint32_t lsb = (p[0] >> byte_bit_ofs) & 1;
233
const uint32_t msb = (p[-2] >> byte_bit_ofs) & 1;
234
const uint32_t val = lsb | (msb << 1);
235
236
return val;
237
}
238
239
// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
240
inline uint32_t get_selector(uint32_t x, uint32_t y) const
241
{
242
return g_etc1_to_selector_index[get_raw_selector(x, y)];
243
}
244
245
// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
246
inline void set_selector(uint32_t x, uint32_t y, uint32_t val)
247
{
248
assert((x | y | val) < 4);
249
const uint32_t bit_index = x * 4 + y;
250
251
uint8_t *p = &m_bytes[7 - (bit_index >> 3)];
252
253
const uint32_t byte_bit_ofs = bit_index & 7;
254
const uint32_t mask = 1 << byte_bit_ofs;
255
256
const uint32_t etc1_val = g_selector_index_to_etc1[val];
257
258
const uint32_t lsb = etc1_val & 1;
259
const uint32_t msb = etc1_val >> 1;
260
261
p[0] &= ~mask;
262
p[0] |= (lsb << byte_bit_ofs);
263
264
p[-2] &= ~mask;
265
p[-2] |= (msb << byte_bit_ofs);
266
}
267
268
// Selector "etc1_val" ranges from 0-3 and is a direct (raw) ETC1 selector.
269
inline void set_raw_selector(uint32_t x, uint32_t y, uint32_t etc1_val)
270
{
271
assert((x | y | etc1_val) < 4);
272
const uint32_t bit_index = x * 4 + y;
273
274
uint8_t* p = &m_bytes[7 - (bit_index >> 3)];
275
276
const uint32_t byte_bit_ofs = bit_index & 7;
277
const uint32_t mask = 1 << byte_bit_ofs;
278
279
const uint32_t lsb = etc1_val & 1;
280
const uint32_t msb = etc1_val >> 1;
281
282
p[0] &= ~mask;
283
p[0] |= (lsb << byte_bit_ofs);
284
285
p[-2] &= ~mask;
286
p[-2] |= (msb << byte_bit_ofs);
287
}
288
289
inline uint32_t get_raw_selector_bits() const
290
{
291
return m_bytes[4] | (m_bytes[5] << 8) | (m_bytes[6] << 16) | (m_bytes[7] << 24);
292
}
293
294
inline void set_raw_selector_bits(uint32_t bits)
295
{
296
m_bytes[4] = static_cast<uint8_t>(bits);
297
m_bytes[5] = static_cast<uint8_t>(bits >> 8);
298
m_bytes[6] = static_cast<uint8_t>(bits >> 16);
299
m_bytes[7] = static_cast<uint8_t>(bits >> 24);
300
}
301
302
inline void set_raw_selector_bits(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
303
{
304
m_bytes[4] = byte0;
305
m_bytes[5] = byte1;
306
m_bytes[6] = byte2;
307
m_bytes[7] = byte3;
308
}
309
310
inline void set_base4_color(uint32_t idx, uint16_t c)
311
{
312
if (idx)
313
{
314
set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
315
set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
316
set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
317
}
318
else
319
{
320
set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
321
set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
322
set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
323
}
324
}
325
326
inline uint16_t get_base4_color(uint32_t idx) const
327
{
328
uint32_t r, g, b;
329
if (idx)
330
{
331
r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
332
g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
333
b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
334
}
335
else
336
{
337
r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
338
g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
339
b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
340
}
341
return static_cast<uint16_t>(b | (g << 4U) | (r << 8U));
342
}
343
344
inline void set_base5_color(uint16_t c)
345
{
346
set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
347
set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
348
set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
349
}
350
351
inline uint16_t get_base5_color() const
352
{
353
const uint32_t r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
354
const uint32_t g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
355
const uint32_t b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
356
return static_cast<uint16_t>(b | (g << 5U) | (r << 10U));
357
}
358
359
void set_delta3_color(uint16_t c)
360
{
361
set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
362
set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
363
set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
364
}
365
366
inline uint16_t get_delta3_color() const
367
{
368
const uint32_t r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
369
const uint32_t g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
370
const uint32_t b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
371
return static_cast<uint16_t>(b | (g << 3U) | (r << 6U));
372
}
373
374
uint64_t determine_selectors(const color_rgba* pSource_pixels, bool perceptual, uint32_t begin_subblock = 0, uint32_t end_subblock = 2)
375
{
376
uint64_t total_error = 0;
377
378
for (uint32_t subblock = begin_subblock; subblock < end_subblock; subblock++)
379
{
380
color_rgba block_colors[4];
381
get_block_colors(block_colors, subblock);
382
383
if (get_flip_bit())
384
{
385
for (uint32_t y = 0; y < 2; y++)
386
{
387
for (uint32_t x = 0; x < 4; x++)
388
{
389
uint32_t best_selector = 0;
390
uint64_t best_error = UINT64_MAX;
391
392
for (uint32_t s = 0; s < 4; s++)
393
{
394
uint64_t err = color_distance(perceptual, block_colors[s], pSource_pixels[x + (subblock * 2 + y) * 4], false);
395
if (err < best_error)
396
{
397
best_error = err;
398
best_selector = s;
399
}
400
}
401
402
set_selector(x, subblock * 2 + y, best_selector);
403
404
total_error += best_error;
405
}
406
}
407
}
408
else
409
{
410
for (uint32_t y = 0; y < 4; y++)
411
{
412
for (uint32_t x = 0; x < 2; x++)
413
{
414
uint32_t best_selector = 0;
415
uint64_t best_error = UINT64_MAX;
416
417
for (uint32_t s = 0; s < 4; s++)
418
{
419
uint64_t err = color_distance(perceptual, block_colors[s], pSource_pixels[(subblock * 2) + x + y * 4], false);
420
if (err < best_error)
421
{
422
best_error = err;
423
best_selector = s;
424
}
425
}
426
427
set_selector(subblock * 2 + x, y, best_selector);
428
429
total_error += best_error;
430
}
431
}
432
}
433
}
434
435
return total_error;
436
}
437
438
color_rgba get_block_color(uint32_t subblock_index, bool scaled) const
439
{
440
color_rgba b;
441
442
if (get_diff_bit())
443
{
444
if (subblock_index)
445
unpack_color5(b, get_base5_color(), get_delta3_color(), scaled);
446
else
447
unpack_color5(b, get_base5_color(), scaled);
448
}
449
else
450
{
451
b = unpack_color4(get_base4_color(subblock_index), scaled);
452
}
453
454
return b;
455
}
456
457
uint32_t get_subblock_index(uint32_t x, uint32_t y) const
458
{
459
if (get_flip_bit())
460
return y >= 2;
461
else
462
return x >= 2;
463
}
464
465
bool get_block_colors(color_rgba* pBlock_colors, uint32_t subblock_index) const
466
{
467
color_rgba b;
468
469
if (get_diff_bit())
470
{
471
if (subblock_index)
472
unpack_color5(b, get_base5_color(), get_delta3_color(), true);
473
else
474
unpack_color5(b, get_base5_color(), true);
475
}
476
else
477
{
478
b = unpack_color4(get_base4_color(subblock_index), true);
479
}
480
481
const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)];
482
483
bool dc = false;
484
485
pBlock_colors[0].set(clamp255(b.r + pInten_table[0], dc), clamp255(b.g + pInten_table[0], dc), clamp255(b.b + pInten_table[0], dc), 255);
486
pBlock_colors[1].set(clamp255(b.r + pInten_table[1], dc), clamp255(b.g + pInten_table[1], dc), clamp255(b.b + pInten_table[1], dc), 255);
487
pBlock_colors[2].set(clamp255(b.r + pInten_table[2], dc), clamp255(b.g + pInten_table[2], dc), clamp255(b.b + pInten_table[2], dc), 255);
488
pBlock_colors[3].set(clamp255(b.r + pInten_table[3], dc), clamp255(b.g + pInten_table[3], dc), clamp255(b.b + pInten_table[3], dc), 255);
489
490
return dc;
491
}
492
493
void get_block_colors_etc1s(color_rgba* pBlock_colors) const
494
{
495
color_rgba b;
496
497
unpack_color5(b, get_base5_color(), true);
498
499
const int* pInten_table = g_etc1_inten_tables[get_inten_table(0)];
500
501
pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);
502
pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);
503
pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);
504
pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);
505
}
506
507
static void get_block_colors_etc1s(color_rgba* pBlock_colors, const color_rgba &base5_color, uint32_t inten_table)
508
{
509
color_rgba b;
510
b.r = (base5_color.r << 3U) | (base5_color.r >> 2U);
511
b.g = (base5_color.g << 3U) | (base5_color.g >> 2U);
512
b.b = (base5_color.b << 3U) | (base5_color.b >> 2U);
513
514
const int* pInten_table = g_etc1_inten_tables[inten_table];
515
516
pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);
517
pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);
518
pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);
519
pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);
520
}
521
522
void get_block_color(color_rgba& color, uint32_t subblock_index, uint32_t selector_index) const
523
{
524
color_rgba b;
525
526
if (get_diff_bit())
527
{
528
if (subblock_index)
529
unpack_color5(b, get_base5_color(), get_delta3_color(), true);
530
else
531
unpack_color5(b, get_base5_color(), true);
532
}
533
else
534
{
535
b = unpack_color4(get_base4_color(subblock_index), true);
536
}
537
538
const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)];
539
540
color.set(clamp255(b.r + pInten_table[selector_index]), clamp255(b.g + pInten_table[selector_index]), clamp255(b.b + pInten_table[selector_index]), 255);
541
}
542
543
bool get_block_low_high_colors(color_rgba* pBlock_colors, uint32_t subblock_index) const
544
{
545
color_rgba b;
546
547
if (get_diff_bit())
548
{
549
if (subblock_index)
550
unpack_color5(b, get_base5_color(), get_delta3_color(), true);
551
else
552
unpack_color5(b, get_base5_color(), true);
553
}
554
else
555
{
556
b = unpack_color4(get_base4_color(subblock_index), true);
557
}
558
559
const int* pInten_table = g_etc1_inten_tables[get_inten_table(subblock_index)];
560
561
bool dc = false;
562
563
pBlock_colors[0].set(clamp255(b.r + pInten_table[0], dc), clamp255(b.g + pInten_table[0], dc), clamp255(b.b + pInten_table[0], dc), 255);
564
pBlock_colors[1].set(clamp255(b.r + pInten_table[3], dc), clamp255(b.g + pInten_table[3], dc), clamp255(b.b + pInten_table[3], dc), 255);
565
566
return dc;
567
}
568
569
static void get_block_colors5(color_rgba *pBlock_colors, const color_rgba &base_color5, uint32_t inten_table, bool scaled = false)
570
{
571
color_rgba b(base_color5);
572
573
if (!scaled)
574
{
575
b.r = (b.r << 3) | (b.r >> 2);
576
b.g = (b.g << 3) | (b.g >> 2);
577
b.b = (b.b << 3) | (b.b >> 2);
578
}
579
580
const int* pInten_table = g_etc1_inten_tables[inten_table];
581
582
pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);
583
pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);
584
pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);
585
pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);
586
}
587
588
static void get_block_colors4(color_rgba *pBlock_colors, const color_rgba &base_color4, uint32_t inten_table, bool scaled = false)
589
{
590
color_rgba b(base_color4);
591
592
if (!scaled)
593
{
594
b.r = (b.r << 4) | b.r;
595
b.g = (b.g << 4) | b.g;
596
b.b = (b.b << 4) | b.b;
597
}
598
599
const int* pInten_table = g_etc1_inten_tables[inten_table];
600
601
pBlock_colors[0].set(clamp255(b.r + pInten_table[0]), clamp255(b.g + pInten_table[0]), clamp255(b.b + pInten_table[0]), 255);
602
pBlock_colors[1].set(clamp255(b.r + pInten_table[1]), clamp255(b.g + pInten_table[1]), clamp255(b.b + pInten_table[1]), 255);
603
pBlock_colors[2].set(clamp255(b.r + pInten_table[2]), clamp255(b.g + pInten_table[2]), clamp255(b.b + pInten_table[2]), 255);
604
pBlock_colors[3].set(clamp255(b.r + pInten_table[3]), clamp255(b.g + pInten_table[3]), clamp255(b.b + pInten_table[3]), 255);
605
}
606
607
uint64_t evaluate_etc1_error(const color_rgba* pBlock_pixels, bool perceptual, int subblock_index = -1) const;
608
void get_subblock_pixels(color_rgba* pPixels, int subblock_index = -1) const;
609
610
void get_selector_range(uint32_t& low, uint32_t& high) const
611
{
612
low = 3;
613
high = 0;
614
for (uint32_t y = 0; y < 4; y++)
615
{
616
for (uint32_t x = 0; x < 4; x++)
617
{
618
const uint32_t s = get_selector(x, y);
619
low = minimum(low, s);
620
high = maximum(high, s);
621
}
622
}
623
}
624
625
void set_block_color4(const color_rgba &c0_unscaled, const color_rgba &c1_unscaled)
626
{
627
set_diff_bit(false);
628
629
set_base4_color(0, pack_color4(c0_unscaled, false));
630
set_base4_color(1, pack_color4(c1_unscaled, false));
631
}
632
633
void set_block_color5(const color_rgba &c0_unscaled, const color_rgba &c1_unscaled)
634
{
635
set_diff_bit(true);
636
637
set_base5_color(pack_color5(c0_unscaled, false));
638
639
int dr = c1_unscaled.r - c0_unscaled.r;
640
int dg = c1_unscaled.g - c0_unscaled.g;
641
int db = c1_unscaled.b - c0_unscaled.b;
642
643
set_delta3_color(pack_delta3(dr, dg, db));
644
}
645
646
void set_block_color5_etc1s(const color_rgba &c_unscaled)
647
{
648
set_diff_bit(true);
649
650
set_base5_color(pack_color5(c_unscaled, false));
651
set_delta3_color(pack_delta3(0, 0, 0));
652
}
653
654
bool set_block_color5_check(const color_rgba &c0_unscaled, const color_rgba &c1_unscaled)
655
{
656
set_diff_bit(true);
657
658
set_base5_color(pack_color5(c0_unscaled, false));
659
660
int dr = c1_unscaled.r - c0_unscaled.r;
661
int dg = c1_unscaled.g - c0_unscaled.g;
662
int db = c1_unscaled.b - c0_unscaled.b;
663
664
if (((dr < cETC1ColorDeltaMin) || (dr > cETC1ColorDeltaMax)) ||
665
((dg < cETC1ColorDeltaMin) || (dg > cETC1ColorDeltaMax)) ||
666
((db < cETC1ColorDeltaMin) || (db > cETC1ColorDeltaMax)))
667
return false;
668
669
set_delta3_color(pack_delta3(dr, dg, db));
670
671
return true;
672
}
673
674
bool set_block_color5_clamp(const color_rgba &c0_unscaled, const color_rgba &c1_unscaled)
675
{
676
set_diff_bit(true);
677
set_base5_color(pack_color5(c0_unscaled, false));
678
679
int dr = c1_unscaled.r - c0_unscaled.r;
680
int dg = c1_unscaled.g - c0_unscaled.g;
681
int db = c1_unscaled.b - c0_unscaled.b;
682
683
dr = clamp<int>(dr, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
684
dg = clamp<int>(dg, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
685
db = clamp<int>(db, cETC1ColorDeltaMin, cETC1ColorDeltaMax);
686
687
set_delta3_color(pack_delta3(dr, dg, db));
688
689
return true;
690
}
691
color_rgba get_selector_color(uint32_t x, uint32_t y, uint32_t s) const
692
{
693
color_rgba block_colors[4];
694
695
get_block_colors(block_colors, get_subblock_index(x, y));
696
697
return block_colors[s];
698
}
699
700
// Base color 5
701
static uint16_t pack_color5(const color_rgba& color, bool scaled, uint32_t bias = 127U);
702
static uint16_t pack_color5(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U);
703
704
static color_rgba unpack_color5(uint16_t packed_color5, bool scaled, uint32_t alpha = 255U);
705
static void unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color, bool scaled);
706
static void unpack_color5(color_rgba& result, uint16_t packed_color5, bool scaled);
707
708
static bool unpack_color5(color_rgba& result, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha = 255U);
709
static bool unpack_color5(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color5, uint16_t packed_delta3, bool scaled, uint32_t alpha = 255U);
710
711
// Delta color 3
712
// Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
713
static uint16_t pack_delta3(const color_rgba_i16& color);
714
static uint16_t pack_delta3(int r, int g, int b);
715
716
// Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
717
static color_rgba_i16 unpack_delta3(uint16_t packed_delta3);
718
static void unpack_delta3(int& r, int& g, int& b, uint16_t packed_delta3);
719
720
static bool try_pack_color5_delta3(const color_rgba *pColor5_unscaled)
721
{
722
int dr = pColor5_unscaled[1].r - pColor5_unscaled[0].r;
723
int dg = pColor5_unscaled[1].g - pColor5_unscaled[0].g;
724
int db = pColor5_unscaled[1].b - pColor5_unscaled[0].b;
725
726
if ((minimum(dr, dg, db) < cETC1ColorDeltaMin) || (maximum(dr, dg, db) > cETC1ColorDeltaMax))
727
return false;
728
729
return true;
730
}
731
732
// Abs color 4
733
static uint16_t pack_color4(const color_rgba& color, bool scaled, uint32_t bias = 127U);
734
static uint16_t pack_color4(uint32_t r, uint32_t g, uint32_t b, bool scaled, uint32_t bias = 127U);
735
736
static color_rgba unpack_color4(uint16_t packed_color4, bool scaled, uint32_t alpha = 255U);
737
static void unpack_color4(uint32_t& r, uint32_t& g, uint32_t& b, uint16_t packed_color4, bool scaled);
738
739
// subblock colors
740
static void get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint32_t table_idx);
741
static bool get_diff_subblock_colors(color_rgba* pDst, uint16_t packed_color5, uint16_t packed_delta3, uint32_t table_idx);
742
static void get_abs_subblock_colors(color_rgba* pDst, uint16_t packed_color4, uint32_t table_idx);
743
744
static inline void unscaled_to_scaled_color(color_rgba& dst, const color_rgba& src, bool color4)
745
{
746
if (color4)
747
{
748
dst.r = src.r | (src.r << 4);
749
dst.g = src.g | (src.g << 4);
750
dst.b = src.b | (src.b << 4);
751
}
752
else
753
{
754
dst.r = (src.r >> 2) | (src.r << 3);
755
dst.g = (src.g >> 2) | (src.g << 3);
756
dst.b = (src.b >> 2) | (src.b << 3);
757
}
758
dst.a = src.a;
759
}
760
761
private:
762
static uint8_t clamp255(int x, bool &did_clamp)
763
{
764
if (x < 0)
765
{
766
did_clamp = true;
767
return 0;
768
}
769
else if (x > 255)
770
{
771
did_clamp = true;
772
return 255;
773
}
774
775
return static_cast<uint8_t>(x);
776
}
777
778
static uint8_t clamp255(int x)
779
{
780
if (x < 0)
781
return 0;
782
else if (x > 255)
783
return 255;
784
785
return static_cast<uint8_t>(x);
786
}
787
};
788
789
typedef basisu::vector<etc_block> etc_block_vec;
790
791
// Returns false if the unpack fails (could be bogus data or ETC2)
792
bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha = false);
793
794
enum basis_etc_quality
795
{
796
cETCQualityFast,
797
cETCQualityMedium,
798
cETCQualitySlow,
799
cETCQualityUber,
800
cETCQualityTotal,
801
};
802
803
struct basis_etc1_pack_params
804
{
805
basis_etc_quality m_quality;
806
bool m_perceptual;
807
bool m_cluster_fit;
808
bool m_force_etc1s;
809
bool m_use_color4;
810
float m_flip_bias;
811
812
inline basis_etc1_pack_params()
813
{
814
clear();
815
}
816
817
void clear()
818
{
819
m_quality = cETCQualitySlow;
820
m_perceptual = true;
821
m_cluster_fit = true;
822
m_force_etc1s = false;
823
m_use_color4 = true;
824
m_flip_bias = 0.0f;
825
}
826
};
827
828
struct etc1_solution_coordinates
829
{
830
inline etc1_solution_coordinates() :
831
m_unscaled_color(0, 0, 0, 0),
832
m_inten_table(0),
833
m_color4(false)
834
{
835
}
836
837
inline etc1_solution_coordinates(uint32_t r, uint32_t g, uint32_t b, uint32_t inten_table, bool color4) :
838
m_unscaled_color((uint8_t)r, (uint8_t)g, (uint8_t)b, 255),
839
m_inten_table((uint8_t)inten_table),
840
m_color4(color4)
841
{
842
}
843
844
inline etc1_solution_coordinates(const color_rgba& c, uint32_t inten_table, bool color4) :
845
m_unscaled_color(c),
846
m_inten_table(inten_table),
847
m_color4(color4)
848
{
849
}
850
851
inline etc1_solution_coordinates(const etc1_solution_coordinates& other)
852
{
853
*this = other;
854
}
855
856
inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs)
857
{
858
m_unscaled_color = rhs.m_unscaled_color;
859
m_inten_table = rhs.m_inten_table;
860
m_color4 = rhs.m_color4;
861
return *this;
862
}
863
864
inline void clear()
865
{
866
m_unscaled_color.clear();
867
m_inten_table = 0;
868
m_color4 = false;
869
}
870
871
inline void init(const color_rgba& c, uint32_t inten_table, bool color4)
872
{
873
m_unscaled_color = c;
874
m_inten_table = inten_table;
875
m_color4 = color4;
876
}
877
878
inline color_rgba get_scaled_color() const
879
{
880
int br, bg, bb;
881
if (m_color4)
882
{
883
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
884
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
885
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
886
}
887
else
888
{
889
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
890
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
891
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
892
}
893
return color_rgba((uint8_t)br, (uint8_t)bg, (uint8_t)bb, 255);
894
}
895
896
// returns true if anything was clamped
897
inline void get_block_colors(color_rgba* pBlock_colors)
898
{
899
int br, bg, bb;
900
if (m_color4)
901
{
902
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
903
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
904
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
905
}
906
else
907
{
908
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
909
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
910
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
911
}
912
const int* pInten_table = g_etc1_inten_tables[m_inten_table];
913
pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0], 255);
914
pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1], 255);
915
pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2], 255);
916
pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3], 255);
917
}
918
919
color_rgba m_unscaled_color;
920
uint32_t m_inten_table;
921
bool m_color4;
922
};
923
924
class etc1_optimizer
925
{
926
BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(etc1_optimizer);
927
928
public:
929
etc1_optimizer()
930
{
931
clear();
932
}
933
934
void clear()
935
{
936
m_pParams = nullptr;
937
m_pResult = nullptr;
938
m_pSorted_luma = nullptr;
939
m_pSorted_luma_indices = nullptr;
940
}
941
942
struct params;
943
944
typedef bool(*evaluate_solution_override_func)(uint64_t &error, const params &p, const color_rgba* pBlock_colors, const uint8_t* pSelectors, const etc1_solution_coordinates& coords);
945
946
struct params : basis_etc1_pack_params
947
{
948
params()
949
{
950
clear();
951
}
952
953
params(const basis_etc1_pack_params& base_params)
954
{
955
clear_optimizer_params();
956
957
*static_cast<basis_etc1_pack_params *>(this) = base_params;
958
}
959
960
void clear()
961
{
962
clear_optimizer_params();
963
}
964
965
void clear_optimizer_params()
966
{
967
basis_etc1_pack_params::clear();
968
969
m_num_src_pixels = 0;
970
m_pSrc_pixels = 0;
971
972
m_use_color4 = false;
973
static const int s_default_scan_delta[] = { 0 };
974
m_pScan_deltas = s_default_scan_delta;
975
m_scan_delta_size = 1;
976
977
m_base_color5.clear();
978
m_constrain_against_base_color5 = false;
979
980
m_refinement = true;
981
982
m_pForce_selectors = nullptr;
983
}
984
985
uint32_t m_num_src_pixels;
986
const color_rgba* m_pSrc_pixels;
987
988
bool m_use_color4;
989
const int* m_pScan_deltas;
990
uint32_t m_scan_delta_size;
991
992
color_rgba m_base_color5;
993
bool m_constrain_against_base_color5;
994
995
bool m_refinement;
996
997
const uint8_t* m_pForce_selectors;
998
};
999
1000
struct results
1001
{
1002
uint64_t m_error;
1003
color_rgba m_block_color_unscaled;
1004
uint32_t m_block_inten_table;
1005
uint32_t m_n;
1006
uint8_t* m_pSelectors;
1007
bool m_block_color4;
1008
1009
inline results& operator= (const results& rhs)
1010
{
1011
m_block_color_unscaled = rhs.m_block_color_unscaled;
1012
m_block_color4 = rhs.m_block_color4;
1013
m_block_inten_table = rhs.m_block_inten_table;
1014
m_error = rhs.m_error;
1015
memcpy(m_pSelectors, rhs.m_pSelectors, minimum(rhs.m_n, m_n));
1016
return *this;
1017
}
1018
};
1019
1020
void init(const params& params, results& result);
1021
bool compute();
1022
1023
const params* get_params() const { return m_pParams; }
1024
1025
private:
1026
struct potential_solution
1027
{
1028
potential_solution() : m_coords(), m_error(UINT64_MAX), m_valid(false)
1029
{
1030
}
1031
1032
etc1_solution_coordinates m_coords;
1033
basisu::vector<uint8_t> m_selectors;
1034
uint64_t m_error;
1035
bool m_valid;
1036
1037
void clear()
1038
{
1039
m_coords.clear();
1040
m_selectors.resize(0);
1041
m_error = UINT64_MAX;
1042
m_valid = false;
1043
}
1044
1045
bool are_selectors_all_equal() const
1046
{
1047
if (!m_selectors.size())
1048
return false;
1049
const uint32_t s = m_selectors[0];
1050
for (uint32_t i = 1; i < m_selectors.size(); i++)
1051
if (m_selectors[i] != s)
1052
return false;
1053
return true;
1054
}
1055
};
1056
1057
const params* m_pParams;
1058
results* m_pResult;
1059
1060
int m_limit;
1061
1062
vec3F m_avg_color;
1063
int m_br, m_bg, m_bb;
1064
int m_max_comp_spread;
1065
basisu::vector<uint16_t> m_luma;
1066
basisu::vector<uint32_t> m_sorted_luma;
1067
basisu::vector<uint32_t> m_sorted_luma_indices;
1068
const uint32_t* m_pSorted_luma_indices;
1069
uint32_t* m_pSorted_luma;
1070
1071
basisu::vector<uint8_t> m_selectors;
1072
basisu::vector<uint8_t> m_best_selectors;
1073
1074
potential_solution m_best_solution;
1075
potential_solution m_trial_solution;
1076
basisu::vector<uint8_t> m_temp_selectors;
1077
1078
enum { cSolutionsTriedHashBits = 10, cTotalSolutionsTriedHashSize = 1 << cSolutionsTriedHashBits, cSolutionsTriedHashMask = cTotalSolutionsTriedHashSize - 1 };
1079
uint8_t m_solutions_tried[cTotalSolutionsTriedHashSize / 8];
1080
1081
void get_nearby_inten_tables(uint32_t idx, int &first_inten_table, int &last_inten_table)
1082
{
1083
first_inten_table = maximum<int>(idx - 1, 0);
1084
last_inten_table = minimum<int>(cETC1IntenModifierValues, idx + 1);
1085
}
1086
1087
bool check_for_redundant_solution(const etc1_solution_coordinates& coords);
1088
bool evaluate_solution_slow(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
1089
bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
1090
1091
inline bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
1092
{
1093
if (m_pParams->m_quality >= cETCQualityMedium)
1094
return evaluate_solution_slow(coords, trial_solution, pBest_solution);
1095
else
1096
return evaluate_solution_fast(coords, trial_solution, pBest_solution);
1097
}
1098
1099
void refine_solution(uint32_t max_refinement_trials);
1100
void compute_internal_neighborhood(int scan_r, int scan_g, int scan_b);
1101
void compute_internal_cluster_fit(uint32_t total_perms_to_try);
1102
};
1103
1104
struct pack_etc1_block_context
1105
{
1106
etc1_optimizer m_optimizer;
1107
};
1108
1109
void pack_etc1_solid_color_init();
1110
uint64_t pack_etc1_block_solid_color(etc_block& block, const uint8_t* pColor);
1111
1112
// ETC EAC
1113
extern const int8_t g_etc2_eac_tables[16][8];
1114
extern const int8_t g_etc2_eac_tables8[16][8];
1115
1116
const uint32_t ETC2_EAC_MIN_VALUE_SELECTOR = 3, ETC2_EAC_MAX_VALUE_SELECTOR = 7;
1117
1118
struct eac_a8_block
1119
{
1120
uint16_t m_base : 8;
1121
uint16_t m_table : 4;
1122
uint16_t m_multiplier : 4;
1123
1124
uint8_t m_selectors[6];
1125
1126
inline uint32_t get_selector(uint32_t x, uint32_t y, uint64_t selector_bits) const
1127
{
1128
assert((x < 4) && (y < 4));
1129
return static_cast<uint32_t>((selector_bits >> (45 - (y + x * 4) * 3)) & 7);
1130
}
1131
1132
inline uint64_t get_selector_bits() const
1133
{
1134
uint64_t pixels = ((uint64_t)m_selectors[0] << 40) | ((uint64_t)m_selectors[1] << 32) | ((uint64_t)m_selectors[2] << 24) | ((uint64_t)m_selectors[3] << 16) | ((uint64_t)m_selectors[4] << 8) | m_selectors[5];
1135
return pixels;
1136
}
1137
1138
inline void set_selector_bits(uint64_t pixels)
1139
{
1140
m_selectors[0] = (uint8_t)(pixels >> 40);
1141
m_selectors[1] = (uint8_t)(pixels >> 32);
1142
m_selectors[2] = (uint8_t)(pixels >> 24);
1143
m_selectors[3] = (uint8_t)(pixels >> 16);
1144
m_selectors[4] = (uint8_t)(pixels >> 8);
1145
m_selectors[5] = (uint8_t)(pixels);
1146
}
1147
1148
void set_selector(uint32_t x, uint32_t y, uint32_t s)
1149
{
1150
assert((x < 4) && (y < 4) && (s < 8));
1151
1152
const uint32_t ofs = 45 - (y + x * 4) * 3;
1153
1154
uint64_t pixels = get_selector_bits();
1155
1156
pixels &= ~(7ULL << ofs);
1157
pixels |= (static_cast<uint64_t>(s) << ofs);
1158
1159
set_selector_bits(pixels);
1160
}
1161
};
1162
1163
struct etc2_rgba_block
1164
{
1165
eac_a8_block m_alpha;
1166
etc_block m_rgb;
1167
};
1168
1169
struct pack_eac_a8_results
1170
{
1171
uint32_t m_base;
1172
uint32_t m_table;
1173
uint32_t m_multiplier;
1174
uint8_vec m_selectors;
1175
uint8_vec m_selectors_temp;
1176
};
1177
1178
uint64_t pack_eac_a8(pack_eac_a8_results& results, const uint8_t* pPixels, uint32_t num_pixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX);
1179
void pack_eac_a8(eac_a8_block* pBlock, const uint8_t* pPixels, uint32_t base_search_rad, uint32_t mul_search_rad, uint32_t table_mask = UINT32_MAX);
1180
1181
} // namespace basisu
1182
1183