Implement ETC1S/ETC2AS image compression

Explanation:

ETC1S encoding is a subset of ETC1, which is using only one color endpoint per 4x4 block (modifier indices are identical for both subblocks, base color is encoded differentially as RGB555 with the differential RGB333 part always set to zero, flip bit is always set to zero).
Usage: crunch_x64.exe -ETC1S input.png -out output.ktx

ETC2AS encoding is a subset of ETC2A encoding which is using ETC1S encoding for color and ETC2A encoding for alpha.
Usage: crunch_x64.exe -ETC2AS input.png -out output.ktx
This commit is contained in:
Alexander Suvorov
2018-10-23 23:16:00 +02:00
parent 4bb735f796
commit 8708900eca
4 changed files with 68 additions and 0 deletions
Binary file not shown.
+24
View File
@@ -1040,6 +1040,30 @@ void dxt_image::set_block_pixels(
rg_etc1::pack_etc1_block(pElement, (uint32*)pPixels, pack_params);
}
}
} else if (m_format == cETC1S) {
crn_etc1_pack_params pack_params;
pack_params.m_perceptual = p.m_perceptual;
pack_params.m_dithering = p.m_dithering;
pack_params.m_quality = p.m_quality <= cCRNDXTQualityFast ? cCRNETCQualityFast : p.m_quality <= cCRNDXTQualityNormal ? cCRNETCQualityMedium : cCRNETCQualitySlow;
pack_etc1s_block(*(etc1_block*)pElement, pPixels, pack_params);
} else if (m_format == cETC2AS) {
for (uint element_index = 0; element_index < m_num_elements_per_block; element_index++, pElement++) {
if (m_element_type[element_index] == cAlphaETC2) {
rg_etc1::etc2a_pack_params pack_params;
pack_params.m_quality = p.m_quality <= cCRNDXTQualityFast ? rg_etc1::cLowQuality : p.m_quality <= cCRNDXTQualityNormal ? rg_etc1::cMediumQuality : rg_etc1::cHighQuality;
pack_params.comp_index = m_element_component_index[element_index];
rg_etc1::pack_etc2_alpha(pElement, (uint32*)pPixels, pack_params);
} else {
crn_etc1_pack_params pack_params;
pack_params.m_perceptual = p.m_perceptual;
pack_params.m_dithering = p.m_dithering;
pack_params.m_quality = p.m_quality <= cCRNDXTQualityFast ? cCRNETCQualityFast : p.m_quality <= cCRNDXTQualityNormal ? cCRNETCQualityMedium : cCRNETCQualitySlow;
pack_etc1s_block(*(etc1_block*)pElement, pPixels, pack_params);
}
}
} else
#if CRNLIB_SUPPORT_SQUISH
if ((p.m_compressor == cCRNDXTCompressorSquish) && ((m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5) || (m_format == cDXT5A))) {
+43
View File
@@ -1580,4 +1580,47 @@ uint64 pack_etc1_block(etc1_block& dst_block, const color_quad_u8* pSrc_pixels,
return best_error;
}
uint64 pack_etc1s_block(etc1_block& dst_block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params) {
uint8 selectors[16];
etc1_optimizer optimizer;
etc1_optimizer::params params;
params.m_pSrc_pixels = pSrc_pixels;
params.m_num_src_pixels = 16;
params.m_use_color4 = false;
params.m_constrain_against_base_color5 = false;
etc1_optimizer::results results;
results.m_pSelectors = selectors;
results.m_n = 16;
optimizer.init(params, results);
const int scan[] = {-4, -3, -2, -1, 0, 1, 2, 3, 4};
params.m_scan_delta_size = pack_params.m_quality == cCRNETCQualitySlow ? CRNLIB_ARRAY_SIZE(scan) : pack_params.m_quality == cCRNETCQualityMedium ? 3 : 1;
params.m_pScan_deltas = scan + ((CRNLIB_ARRAY_SIZE(scan) - params.m_scan_delta_size) >> 1);
optimizer.compute();
if (params.m_quality >= cCRNETCQualityMedium && results.m_error > 6000) {
const int refine_medium[] = {-3, -2, 2, 3};
const int refine_high[] = {-8, -7, -6, -5, 5, 6, 7, 8};
if (params.m_quality == cCRNETCQualityMedium) {
params.m_scan_delta_size = CRNLIB_ARRAY_SIZE(refine_medium);
params.m_pScan_deltas = refine_medium;
} else {
params.m_scan_delta_size = results.m_error > 12000 ? CRNLIB_ARRAY_SIZE(refine_high) : 2;
params.m_pScan_deltas = refine_high + ((CRNLIB_ARRAY_SIZE(refine_high) - params.m_scan_delta_size) >> 1);
}
optimizer.compute();
}
uint32 selector = 0;
for (uint32 i = 0, t = 8, h = 0; h < 4; h++, t -= 15) {
for (uint32 w = 0; w < 4; w++, t += 4, i++) {
uint32 s = g_selector_index_to_etc1[selectors[i]];
selector |= (s >> 1 | (s & 1) << 16) << (t & 15);
}
}
dst_block.m_uint64 = (uint64)selector << 32 | results.m_block_inten_table << 29 | results.m_block_inten_table << 26 | 1 << 25 | (results.m_block_color_unscaled.m_u32 & 0xFFFFFF) << 3;
return results.m_error;
}
} // namespace crnlib
+1
View File
@@ -538,5 +538,6 @@ struct pack_etc1_block_context {
void pack_etc1_block_init();
uint64 pack_etc1_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params, pack_etc1_block_context& context);
uint64 pack_etc1s_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params);
} // namespace crnlib