Commit b6d684ec by Rémi Verschelde

basis_universal: Update to upstream commit from Jan 4, 2020

BinomialLLC/basis_universal@895ee8ee7e04f22267f8d16d46de04d5a01d63ac.
parent ef51726f
......@@ -91,7 +91,7 @@ static PoolVector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Ima
//params.m_quality_level = 0;
//params.m_disable_hierarchical_endpoint_codebooks = true;
//params.m_no_selector_rdo = true;
params.m_no_auto_global_sel_pal = true;
params.m_auto_global_sel_pal = false;
basisu::job_pool jpool(OS::get_singleton()->get_processor_count());
params.m_pJob_pool = &jpool;
......@@ -170,13 +170,13 @@ static Ref<Image> basis_universal_unpacker(const PoolVector<uint8_t> &p_buffer)
case BASIS_DECOMPRESS_RG: {
if (VS::get_singleton()->has_os_feature("rgtc")) {
format = basist::cTFBC5; // get this from renderer
format = basist::transcoder_texture_format::cTFBC5; // get this from renderer
imgfmt = Image::FORMAT_RGTC_RG;
} else if (VS::get_singleton()->has_os_feature("etc2")) {
//unfortunately, basis universal does not support
//
ERR_FAIL_V(image); //unimplemented here
//format = basist::cTFETC1; // get this from renderer
//format = basist::transcoder_texture_format::cTFETC1; // get this from renderer
//imgfmt = Image::FORMAT_RGTC_RG;
} else {
//decompress
......@@ -184,47 +184,47 @@ static Ref<Image> basis_universal_unpacker(const PoolVector<uint8_t> &p_buffer)
} break;
case BASIS_DECOMPRESS_RGB: {
if (VS::get_singleton()->has_os_feature("bptc")) {
format = basist::cTFBC7_M6_OPAQUE_ONLY; // get this from renderer
format = basist::transcoder_texture_format::cTFBC7_M6_OPAQUE_ONLY; // get this from renderer
imgfmt = Image::FORMAT_BPTC_RGBA;
} else if (VS::get_singleton()->has_os_feature("s3tc")) {
format = basist::cTFBC1; // get this from renderer
format = basist::transcoder_texture_format::cTFBC1; // get this from renderer
imgfmt = Image::FORMAT_DXT1;
} else if (VS::get_singleton()->has_os_feature("etc")) {
format = basist::cTFETC1; // get this from renderer
format = basist::transcoder_texture_format::cTFETC1; // get this from renderer
imgfmt = Image::FORMAT_ETC;
} else {
format = basist::cTFBGR565; // get this from renderer
format = basist::transcoder_texture_format::cTFBGR565; // get this from renderer
imgfmt = Image::FORMAT_RGB565;
}
} break;
case BASIS_DECOMPRESS_RGBA: {
if (VS::get_singleton()->has_os_feature("bptc")) {
format = basist::cTFBC7_M5; // get this from renderer
format = basist::transcoder_texture_format::cTFBC7_M5; // get this from renderer
imgfmt = Image::FORMAT_BPTC_RGBA;
} else if (VS::get_singleton()->has_os_feature("s3tc")) {
format = basist::cTFBC3; // get this from renderer
format = basist::transcoder_texture_format::cTFBC3; // get this from renderer
imgfmt = Image::FORMAT_DXT5;
} else if (VS::get_singleton()->has_os_feature("etc2")) {
format = basist::cTFETC2; // get this from renderer
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
imgfmt = Image::FORMAT_ETC2_RGBA8;
} else {
//gles2 most likely
format = basist::cTFRGBA4444; // get this from renderer
format = basist::transcoder_texture_format::cTFRGBA4444; // get this from renderer
imgfmt = Image::FORMAT_RGBA4444;
}
} break;
case BASIS_DECOMPRESS_RG_AS_RA: {
if (VS::get_singleton()->has_os_feature("s3tc")) {
format = basist::cTFBC3; // get this from renderer
format = basist::transcoder_texture_format::cTFBC3; // get this from renderer
imgfmt = Image::FORMAT_DXT5_RA_AS_RG;
} else if (VS::get_singleton()->has_os_feature("etc2")) {
format = basist::cTFETC2; // get this from renderer
format = basist::transcoder_texture_format::cTFETC2; // get this from renderer
imgfmt = Image::FORMAT_ETC2_RGBA8;
} else {
//gles2 most likely, bad for normalmaps, nothing to do about this.
format = basist::cTFRGBA32;
format = basist::transcoder_texture_format::cTFRGBA32;
imgfmt = Image::FORMAT_RGBA8;
}
} break;
......
......@@ -16,7 +16,7 @@ Subcategories (`###` level) where needed are separated by a single empty line.
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal
- Version: git (6afb2fc, 2019)
- Version: git (895ee8e, 2020)
- License: Apache 2.0
Files extracted from upstream source:
......
......@@ -597,7 +597,7 @@ namespace basisu
const uint32_t num_blocks_y = m_slices[slice_index].m_num_blocks_y;
gpu_image gi;
gi.init(cETC1, width, height);
gi.init(texture_format::cETC1, width, height);
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
{
......
......@@ -32,7 +32,7 @@ namespace basisu
for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++)
m_header.m_total_images = maximum<uint32_t>(m_header.m_total_images, encoder_output.m_slice_desc[i].m_source_file_index + 1);
m_header.m_format = basist::cETC1;
m_header.m_format = 0;// basist::block_format::cETC1;
m_header.m_flags = 0;
if (encoder_output.m_etc1s)
......
......@@ -57,7 +57,7 @@ namespace basisu
PRINT_BOOL_VALUE(m_debug);
PRINT_BOOL_VALUE(m_debug_images);
PRINT_BOOL_VALUE(m_global_sel_pal);
PRINT_BOOL_VALUE(m_no_auto_global_sel_pal);
PRINT_BOOL_VALUE(m_auto_global_sel_pal);
PRINT_BOOL_VALUE(m_compression_level);
PRINT_BOOL_VALUE(m_no_hybrid_sel_cb);
PRINT_BOOL_VALUE(m_perceptual);
......@@ -774,7 +774,7 @@ namespace basisu
}
m_auto_global_sel_pal = false;
if (!m_params.m_global_sel_pal && !m_params.m_no_auto_global_sel_pal)
if (!m_params.m_global_sel_pal && m_params.m_auto_global_sel_pal)
{
const float bits_per_selector_cluster = 31.0f;
double selector_codebook_bpp_est = (bits_per_selector_cluster * selector_clusters) / total_texels;
......@@ -860,7 +860,7 @@ namespace basisu
const uint32_t width = num_blocks_x * 4;
const uint32_t height = num_blocks_y * 4;
m_frontend_output_textures[i].init(cETC1, width, height);
m_frontend_output_textures[i].init(texture_format::cETC1, width, height);
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
......@@ -875,7 +875,7 @@ namespace basisu
}
#endif
m_best_etc1s_images[i].init(cETC1, width, height);
m_best_etc1s_images[i].init(texture_format::cETC1, width, height);
for (uint32_t block_y = 0; block_y < num_blocks_y; block_y++)
for (uint32_t block_x = 0; block_x < num_blocks_x; block_x++)
memcpy(m_best_etc1s_images[i].get_block_ptr(block_x, block_y, 0), &m_frontend.get_etc1s_block(slice_desc.m_first_block_index + block_x + block_y * num_blocks_x), sizeof(etc_block));
......@@ -970,12 +970,12 @@ namespace basisu
for (uint32_t i = 0; i < m_slice_descs.size(); i++)
{
gpu_image decoded_texture;
decoded_texture.init(cETC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
decoded_texture.init(texture_format::cETC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
tm.start();
if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::cETC1, 8))
reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cETC1, 8))
{
error_printf("Transcoding failed to ETC1 on slice %u!\n", i);
return false;
......@@ -1008,12 +1008,12 @@ namespace basisu
for (uint32_t i = 0; i < m_slice_descs.size(); i++)
{
gpu_image decoded_texture;
decoded_texture.init(cBC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
decoded_texture.init(texture_format::cBC1, m_slice_descs[i].m_width, m_slice_descs[i].m_height);
tm.start();
if (!decoder.transcode_slice(&comp_data[0], (uint32_t)comp_data.size(), i,
reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::cBC1, 8))
reinterpret_cast<etc_block *>(decoded_texture.get_ptr()), m_slice_descs[i].m_num_blocks_x * m_slice_descs[i].m_num_blocks_y, basist::block_format::cBC1, 8))
{
error_printf("Transcoding failed to BC1 on slice %u!\n", i);
return false;
......@@ -1066,9 +1066,7 @@ namespace basisu
{
const uint8_vec &comp_data = m_basis_file.get_compressed_data();
std::string basis_filename(m_params.m_out_filename);
string_remove_extension(basis_filename);
basis_filename += ".basis";
const std::string& basis_filename = m_params.m_out_filename;
if (!write_vec_to_file(basis_filename.c_str(), comp_data))
{
......
......@@ -207,7 +207,7 @@ namespace basisu
m_debug.clear();
m_debug_images.clear();
m_global_sel_pal.clear();
m_no_auto_global_sel_pal.clear();
m_auto_global_sel_pal.clear();
m_no_hybrid_sel_cb.clear();
m_perceptual.clear();
m_no_selector_rdo.clear();
......@@ -279,7 +279,7 @@ namespace basisu
param<int> m_compression_level;
bool_param<false> m_global_sel_pal;
bool_param<false> m_no_auto_global_sel_pal;
bool_param<false> m_auto_global_sel_pal;
// Frontend/backend codec parameters
bool_param<false> m_no_hybrid_sel_cb;
......
......@@ -1070,7 +1070,7 @@ namespace basisu
assert(node.is_leaf());
var_heap.delete_top();
if (node.m_training_vecs.size() > 1)
{
if (split_node(node_index, var_heap, l_children, r_children))
......@@ -1197,11 +1197,11 @@ namespace basisu
}
if ((l_child.m_var > 0.0f) && (l_child.m_training_vecs.size() > 1))
var_heap.add_heap(l_child_index, l_var);
var_heap.add_heap(l_child_index, l_child.m_var);
if ((r_child.m_var > 0.0f) && (r_child.m_training_vecs.size() > 1))
var_heap.add_heap(r_child_index, r_var);
var_heap.add_heap(r_child_index, r_child.m_var);
return true;
}
......
......@@ -343,6 +343,7 @@ namespace basisu
cur_blk.set_block_color5_etc1s(get_endpoint_cluster_unscaled_color(endpoint_cluster_index, false));
cur_blk.set_inten_tables_etc1s(get_endpoint_cluster_inten_table(endpoint_cluster_index, false));
cur_blk.set_raw_selector_bits(get_selector_cluster_selector_bits(old_selector_cluster_index).get_raw_selector_bits());
cur_blk.set_flip_bit(true);
const uint64_t cur_err = cur_blk.evaluate_etc1_error(get_source_pixel_block(block_index).get_ptr(), m_params.m_perceptual);
......@@ -2385,7 +2386,7 @@ namespace basisu
void basisu_frontend::dump_debug_image(const char *pFilename, uint32_t first_block, uint32_t num_blocks_x, uint32_t num_blocks_y, bool output_blocks)
{
gpu_image g;
g.init(cETC1, num_blocks_x * 4, num_blocks_y * 4);
g.init(texture_format::cETC1, num_blocks_x * 4, num_blocks_y * 4);
for (uint32_t y = 0; y < num_blocks_y; y++)
{
......
......@@ -596,33 +596,375 @@ namespace basisu
return true;
}
struct fxt1_block
{
union
{
struct
{
uint64_t m_t00 : 2;
uint64_t m_t01 : 2;
uint64_t m_t02 : 2;
uint64_t m_t03 : 2;
uint64_t m_t04 : 2;
uint64_t m_t05 : 2;
uint64_t m_t06 : 2;
uint64_t m_t07 : 2;
uint64_t m_t08 : 2;
uint64_t m_t09 : 2;
uint64_t m_t10 : 2;
uint64_t m_t11 : 2;
uint64_t m_t12 : 2;
uint64_t m_t13 : 2;
uint64_t m_t14 : 2;
uint64_t m_t15 : 2;
uint64_t m_t16 : 2;
uint64_t m_t17 : 2;
uint64_t m_t18 : 2;
uint64_t m_t19 : 2;
uint64_t m_t20 : 2;
uint64_t m_t21 : 2;
uint64_t m_t22 : 2;
uint64_t m_t23 : 2;
uint64_t m_t24 : 2;
uint64_t m_t25 : 2;
uint64_t m_t26 : 2;
uint64_t m_t27 : 2;
uint64_t m_t28 : 2;
uint64_t m_t29 : 2;
uint64_t m_t30 : 2;
uint64_t m_t31 : 2;
} m_lo;
uint64_t m_lo_bits;
uint8_t m_sels[8];
};
union
{
struct
{
#ifdef BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING
// This is the format that 3DFX's DECOMP.EXE tool expects, which I'm assuming is what the actual 3DFX hardware wanted.
// Unfortunately, color0/color1 and color2/color3 are flipped relative to the official OpenGL extension and Intel's documentation!
uint64_t m_b1 : 5;
uint64_t m_g1 : 5;
uint64_t m_r1 : 5;
uint64_t m_b0 : 5;
uint64_t m_g0 : 5;
uint64_t m_r0 : 5;
uint64_t m_b3 : 5;
uint64_t m_g3 : 5;
uint64_t m_r3 : 5;
uint64_t m_b2 : 5;
uint64_t m_g2 : 5;
uint64_t m_r2 : 5;
#else
// Intel's encoding, and the encoding in the OpenGL FXT1 spec.
uint64_t m_b0 : 5;
uint64_t m_g0 : 5;
uint64_t m_r0 : 5;
uint64_t m_b1 : 5;
uint64_t m_g1 : 5;
uint64_t m_r1 : 5;
uint64_t m_b2 : 5;
uint64_t m_g2 : 5;
uint64_t m_r2 : 5;
uint64_t m_b3 : 5;
uint64_t m_g3 : 5;
uint64_t m_r3 : 5;
#endif
uint64_t m_alpha : 1;
uint64_t m_glsb : 2;
uint64_t m_mode : 1;
} m_hi;
uint64_t m_hi_bits;
};
};
static color_rgba expand_565(const color_rgba& c)
{
return color_rgba((c.r << 3) | (c.r >> 2), (c.g << 2) | (c.g >> 4), (c.b << 3) | (c.b >> 2), 255);
}
// We only support CC_MIXED non-alpha blocks here because that's the only mode the transcoder uses at the moment.
bool unpack_fxt1(const void *p, color_rgba *pPixels)
{
const fxt1_block* pBlock = static_cast<const fxt1_block*>(p);
if (pBlock->m_hi.m_mode == 0)
return false;
if (pBlock->m_hi.m_alpha == 1)
return false;
color_rgba colors[4];
colors[0].r = pBlock->m_hi.m_r0;
colors[0].g = (uint8_t)((pBlock->m_hi.m_g0 << 1) | ((pBlock->m_lo.m_t00 >> 1) ^ (pBlock->m_hi.m_glsb & 1)));
colors[0].b = pBlock->m_hi.m_b0;
colors[0].a = 255;
colors[1].r = pBlock->m_hi.m_r1;
colors[1].g = (uint8_t)((pBlock->m_hi.m_g1 << 1) | (pBlock->m_hi.m_glsb & 1));
colors[1].b = pBlock->m_hi.m_b1;
colors[1].a = 255;
colors[2].r = pBlock->m_hi.m_r2;
colors[2].g = (uint8_t)((pBlock->m_hi.m_g2 << 1) | ((pBlock->m_lo.m_t16 >> 1) ^ (pBlock->m_hi.m_glsb >> 1)));
colors[2].b = pBlock->m_hi.m_b2;
colors[2].a = 255;
colors[3].r = pBlock->m_hi.m_r3;
colors[3].g = (uint8_t)((pBlock->m_hi.m_g3 << 1) | (pBlock->m_hi.m_glsb >> 1));
colors[3].b = pBlock->m_hi.m_b3;
colors[3].a = 255;
for (uint32_t i = 0; i < 4; i++)
colors[i] = expand_565(colors[i]);
color_rgba block0_colors[4];
block0_colors[0] = colors[0];
block0_colors[1] = color_rgba((colors[0].r * 2 + colors[1].r + 1) / 3, (colors[0].g * 2 + colors[1].g + 1) / 3, (colors[0].b * 2 + colors[1].b + 1) / 3, 255);
block0_colors[2] = color_rgba((colors[1].r * 2 + colors[0].r + 1) / 3, (colors[1].g * 2 + colors[0].g + 1) / 3, (colors[1].b * 2 + colors[0].b + 1) / 3, 255);
block0_colors[3] = colors[1];
for (uint32_t i = 0; i < 16; i++)
{
const uint32_t sel = (pBlock->m_sels[i >> 2] >> ((i & 3) * 2)) & 3;
const uint32_t x = i & 3;
const uint32_t y = i >> 2;
pPixels[x + y * 8] = block0_colors[sel];
}
color_rgba block1_colors[4];
block1_colors[0] = colors[2];
block1_colors[1] = color_rgba((colors[2].r * 2 + colors[3].r + 1) / 3, (colors[2].g * 2 + colors[3].g + 1) / 3, (colors[2].b * 2 + colors[3].b + 1) / 3, 255);
block1_colors[2] = color_rgba((colors[3].r * 2 + colors[2].r + 1) / 3, (colors[3].g * 2 + colors[2].g + 1) / 3, (colors[3].b * 2 + colors[2].b + 1) / 3, 255);
block1_colors[3] = colors[3];
for (uint32_t i = 0; i < 16; i++)
{
const uint32_t sel = (pBlock->m_sels[4 + (i >> 2)] >> ((i & 3) * 2)) & 3;
const uint32_t x = i & 3;
const uint32_t y = i >> 2;
pPixels[4 + x + y * 8] = block1_colors[sel];
}
return true;
}
struct pvrtc2_block
{
uint8_t m_modulation[4];
union
{
union
{
// Opaque mode: RGB colora=554 and colorb=555
struct
{
uint32_t m_mod_flag : 1;
uint32_t m_blue_a : 4;
uint32_t m_green_a : 5;
uint32_t m_red_a : 5;
uint32_t m_hard_flag : 1;
uint32_t m_blue_b : 5;
uint32_t m_green_b : 5;
uint32_t m_red_b : 5;
uint32_t m_opaque_flag : 1;
} m_opaque_color_data;
// Transparent mode: RGBA colora=4433 and colorb=4443
struct
{
uint32_t m_mod_flag : 1;
uint32_t m_blue_a : 3;
uint32_t m_green_a : 4;
uint32_t m_red_a : 4;
uint32_t m_alpha_a : 3;
uint32_t m_hard_flag : 1;
uint32_t m_blue_b : 4;
uint32_t m_green_b : 4;
uint32_t m_red_b : 4;
uint32_t m_alpha_b : 3;
uint32_t m_opaque_flag : 1;
} m_trans_color_data;
};
uint32_t m_color_data_bits;
};
};
static color_rgba convert_rgb_555_to_888(const color_rgba& col)
{
return color_rgba((col[0] << 3) | (col[0] >> 2), (col[1] << 3) | (col[1] >> 2), (col[2] << 3) | (col[2] >> 2), 255);
}
static color_rgba convert_rgba_5554_to_8888(const color_rgba& col)
{
return color_rgba((col[0] << 3) | (col[0] >> 2), (col[1] << 3) | (col[1] >> 2), (col[2] << 3) | (col[2] >> 2), (col[3] << 4) | col[3]);
}
// PVRTC2 is currently limited to only what our transcoder outputs (non-interpolated, hard_flag=1 modulation=0). In this mode, PVRTC2 looks much like BC1/ATC.
bool unpack_pvrtc2(const void *p, color_rgba *pPixels)
{
const pvrtc2_block* pBlock = static_cast<const pvrtc2_block*>(p);
if ((!pBlock->m_opaque_color_data.m_hard_flag) || (pBlock->m_opaque_color_data.m_mod_flag))
{
// This mode isn't supported by the transcoder, so we aren't bothering with it here.
return false;
}
color_rgba colors[4];
if (pBlock->m_opaque_color_data.m_opaque_flag)
{
// colora=554
color_rgba color_a(pBlock->m_opaque_color_data.m_red_a, pBlock->m_opaque_color_data.m_green_a, (pBlock->m_opaque_color_data.m_blue_a << 1) | (pBlock->m_opaque_color_data.m_blue_a >> 3), 255);
// colora=555
color_rgba color_b(pBlock->m_opaque_color_data.m_red_b, pBlock->m_opaque_color_data.m_green_b, pBlock->m_opaque_color_data.m_blue_b, 255);
colors[0] = convert_rgb_555_to_888(color_a);
colors[3] = convert_rgb_555_to_888(color_b);
colors[1].set((colors[0].r * 5 + colors[3].r * 3) / 8, (colors[0].g * 5 + colors[3].g * 3) / 8, (colors[0].b * 5 + colors[3].b * 3) / 8, 255);
colors[2].set((colors[0].r * 3 + colors[3].r * 5) / 8, (colors[0].g * 3 + colors[3].g * 5) / 8, (colors[0].b * 3 + colors[3].b * 5) / 8, 255);
}
else
{
// colora=4433
color_rgba color_a(
(pBlock->m_trans_color_data.m_red_a << 1) | (pBlock->m_trans_color_data.m_red_a >> 3),
(pBlock->m_trans_color_data.m_green_a << 1) | (pBlock->m_trans_color_data.m_green_a >> 3),
(pBlock->m_trans_color_data.m_blue_a << 2) | (pBlock->m_trans_color_data.m_blue_a >> 1),
pBlock->m_trans_color_data.m_alpha_a << 1);
//colorb=4443
color_rgba color_b(
(pBlock->m_trans_color_data.m_red_b << 1) | (pBlock->m_trans_color_data.m_red_b >> 3),
(pBlock->m_trans_color_data.m_green_b << 1) | (pBlock->m_trans_color_data.m_green_b >> 3),
(pBlock->m_trans_color_data.m_blue_b << 1) | (pBlock->m_trans_color_data.m_blue_b >> 3),
(pBlock->m_trans_color_data.m_alpha_b << 1) | 1);
colors[0] = convert_rgba_5554_to_8888(color_a);
colors[3] = convert_rgba_5554_to_8888(color_b);
}
colors[1].set((colors[0].r * 5 + colors[3].r * 3) / 8, (colors[0].g * 5 + colors[3].g * 3) / 8, (colors[0].b * 5 + colors[3].b * 3) / 8, (colors[0].a * 5 + colors[3].a * 3) / 8);
colors[2].set((colors[0].r * 3 + colors[3].r * 5) / 8, (colors[0].g * 3 + colors[3].g * 5) / 8, (colors[0].b * 3 + colors[3].b * 5) / 8, (colors[0].a * 3 + colors[3].a * 5) / 8);
for (uint32_t i = 0; i < 16; i++)
{
const uint32_t sel = (pBlock->m_modulation[i >> 2] >> ((i & 3) * 2)) & 3;
pPixels[i] = colors[sel];
}
return true;
}
struct etc2_eac_r11
{
uint64_t m_base : 8;
uint64_t m_table : 4;
uint64_t m_mul : 4;
uint64_t m_sels_0 : 8;
uint64_t m_sels_1 : 8;
uint64_t m_sels_2 : 8;
uint64_t m_sels_3 : 8;
uint64_t m_sels_4 : 8;
uint64_t m_sels_5 : 8;
uint64_t get_sels() const
{
return ((uint64_t)m_sels_0 << 40U) | ((uint64_t)m_sels_1 << 32U) | ((uint64_t)m_sels_2 << 24U) | ((uint64_t)m_sels_3 << 16U) | ((uint64_t)m_sels_4 << 8U) | m_sels_5;
}
void set_sels(uint64_t v)
{
m_sels_0 = (v >> 40U) & 0xFF;
m_sels_1 = (v >> 32U) & 0xFF;
m_sels_2 = (v >> 24U) & 0xFF;
m_sels_3 = (v >> 16U) & 0xFF;
m_sels_4 = (v >> 8U) & 0xFF;
m_sels_5 = v & 0xFF;
}
};
struct etc2_eac_rg11
{
etc2_eac_r11 m_c[2];
};
static void unpack_etc2_eac_r(const etc2_eac_r11* p, color_rgba* pPixels, uint32_t c)
{
const uint64_t sels = p->get_sels();
const int base = (int)p->m_base * 8 + 4;
const int mul = p->m_mul ? ((int)p->m_mul * 8) : 1;
const int table = (int)p->m_table;
for (uint32_t y = 0; y < 4; y++)
{
for (uint32_t x = 0; x < 4; x++)
{
const uint32_t shift = 45 - ((y + x * 4) * 3);
const uint32_t sel = (uint32_t)((sels >> shift) & 7);
int val = base + g_etc2_eac_tables[table][sel] * mul;
val = clamp<int>(val, 0, 2047);
// Convert to 8-bits with rounding
pPixels[x + y * 4].m_comps[c] = static_cast<uint8_t>((val * 255 + 1024) / 2047);
} // x
} // y
}
void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels)
{
for (uint32_t c = 0; c < 2; c++)
{
const etc2_eac_r11* pBlock = &static_cast<const etc2_eac_rg11*>(p)->m_c[c];
unpack_etc2_eac_r(pBlock, pPixels, c);
}
}
// Unpacks to RGBA, R, RG, or A
bool unpack_block(texture_format fmt, const void* pBlock, color_rgba* pPixels)
{
switch (fmt)
{
case cBC1:
case texture_format::cBC1:
{
unpack_bc1(pBlock, pPixels, true);
break;
}
case cBC3:
case texture_format::cBC3:
{
return unpack_bc3(pBlock, pPixels);
}
case cBC4:
case texture_format::cBC4:
{
// Unpack to R
unpack_bc4(pBlock, &pPixels[0].r, sizeof(color_rgba));
break;
}
case cBC5:
case texture_format::cBC5:
{
unpack_bc5(pBlock, pPixels);
break;
}
case cBC7:
case texture_format::cBC7:
{
// We only support modes 5 and 6.
if (!unpack_bc7_mode5(pBlock, pPixels))
......@@ -634,42 +976,62 @@ namespace basisu
break;
}
// Full ETC2 color blocks (planar/T/H modes) is currently unsupported in basisu, but we do support ETC2 with alpha (using ETC1 for color)
case cETC2_RGB:
case cETC1:
case cETC1S:
case texture_format::cETC2_RGB:
case texture_format::cETC1:
case texture_format::cETC1S:
{
return unpack_etc1(*static_cast<const etc_block*>(pBlock), pPixels);
}
case cETC2_RGBA:
case texture_format::cETC2_RGBA:
{
if (!unpack_etc1(static_cast<const etc_block*>(pBlock)[1], pPixels))
return false;
unpack_etc2_eac(pBlock, pPixels);
break;
}
case cETC2_ALPHA:
case texture_format::cETC2_ALPHA:
{
// Unpack to A
unpack_etc2_eac(pBlock, pPixels);
break;
}
case cASTC4x4:
case texture_format::cASTC4x4:
{
const bool astc_srgb = false;
basisu_astc::astc::decompress(reinterpret_cast<uint8_t*>(pPixels), static_cast<const uint8_t*>(pBlock), astc_srgb, 4, 4);
break;
}
case cATC_RGB:
case texture_format::cATC_RGB:
{
unpack_atc(pBlock, pPixels);
break;
}
case cATC_RGBA_INTERPOLATED_ALPHA:
case texture_format::cATC_RGBA_INTERPOLATED_ALPHA:
{
unpack_atc(static_cast<const uint8_t*>(pBlock) + 8, pPixels);
unpack_bc4(pBlock, &pPixels[0].a, sizeof(color_rgba));
break;
}
case texture_format::cFXT1_RGB:
{
unpack_fxt1(pBlock, pPixels);
break;
}
case texture_format::cPVRTC2_4_RGBA:
{
unpack_pvrtc2(pBlock, pPixels);
break;
}
case texture_format::cETC2_R11_EAC:
{
unpack_etc2_eac_r(static_cast<const etc2_eac_r11 *>(pBlock), pPixels, 0);
break;
}
case texture_format::cETC2_RG11_EAC:
{
unpack_etc2_eac_rg(pBlock, pPixels);
break;
}
default:
{
assert(0);
......@@ -680,7 +1042,7 @@ namespace basisu
return true;
}
bool gpu_image::unpack(image& img, bool pvrtc_wrap_addressing) const
bool gpu_image::unpack(image& img) const
{
img.resize(get_pixel_width(), get_pixel_height());
img.set_all(g_black_color);
......@@ -688,9 +1050,9 @@ namespace basisu
if (!img.get_width() || !img.get_height())
return true;
if ((m_fmt == cPVRTC1_4_RGB) || (m_fmt == cPVRTC1_4_RGBA))
if ((m_fmt == texture_format::cPVRTC1_4_RGB) || (m_fmt == texture_format::cPVRTC1_4_RGBA))
{
pvrtc4_image pi(m_width, m_height, pvrtc_wrap_addressing);
pvrtc4_image pi(m_width, m_height);
if (get_total_blocks() != pi.get_total_blocks())
return false;
......@@ -704,6 +1066,7 @@ namespace basisu
return true;
}
assert((m_block_width <= cMaxBlockSize) && (m_block_height <= cMaxBlockSize));
color_rgba pixels[cMaxBlockSize * cMaxBlockSize];
for (uint32_t i = 0; i < cMaxBlockSize * cMaxBlockSize; i++)
pixels[i] = g_black_color;
......@@ -751,7 +1114,12 @@ namespace basisu
KTX_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0,
KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0,
KTX_ATC_RGB_AMD = 0x8C92,
KTX_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE
KTX_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x87EE,
KTX_COMPRESSED_RGB_FXT1_3DFX = 0x86B0,
KTX_COMPRESSED_RGBA_FXT1_3DFX = 0x86B1,
KTX_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG = 0x9138,
KTX_COMPRESSED_R11_EAC = 0x9270,
KTX_COMPRESSED_RG11_EAC = 0x9272
};
struct ktx_header
......@@ -784,7 +1152,7 @@ namespace basisu
}
uint32_t width = 0, height = 0, total_levels = 0;
basisu::texture_format fmt = cInvalidTextureFormat;
basisu::texture_format fmt = texture_format::cInvalidTextureFormat;
if (cubemap_flag)
{
......@@ -851,80 +1219,103 @@ namespace basisu
switch (fmt)
{
case cBC1:
case texture_format::cBC1:
{
internal_fmt = KTX_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
}
case cBC3:
case texture_format::cBC3:
{
internal_fmt = KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT;
base_internal_fmt = KTX_RGBA;
break;
}
case cBC4:
case texture_format::cBC4:
{
internal_fmt = KTX_COMPRESSED_RED_RGTC1_EXT;// KTX_COMPRESSED_LUMINANCE_LATC1_EXT;
base_internal_fmt = KTX_RED;
break;
}
case cBC5:
case texture_format::cBC5:
{
internal_fmt = KTX_COMPRESSED_RED_GREEN_RGTC2_EXT;
base_internal_fmt = KTX_RG;
break;
}
case cETC1:
case cETC1S:
case texture_format::cETC1:
case texture_format::cETC1S:
{
internal_fmt = KTX_ETC1_RGB8_OES;
break;
}
case cETC2_RGB:
case texture_format::cETC2_RGB:
{
internal_fmt = KTX_COMPRESSED_RGB8_ETC2;
break;
}
case cETC2_RGBA:
case texture_format::cETC2_RGBA:
{
internal_fmt = KTX_COMPRESSED_RGBA8_ETC2_EAC;
base_internal_fmt = KTX_RGBA;
break;
}
case cBC7:
case texture_format::cBC7:
{
internal_fmt = KTX_COMPRESSED_RGBA_BPTC_UNORM;
base_internal_fmt = KTX_RGBA;
break;
}
case cPVRTC1_4_RGB:
case texture_format::cPVRTC1_4_RGB:
{
internal_fmt = KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
break;
}
case cPVRTC1_4_RGBA:
case texture_format::cPVRTC1_4_RGBA:
{
internal_fmt = KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
base_internal_fmt = KTX_RGBA;
break;
}
case cASTC4x4:
case texture_format::cASTC4x4:
{
internal_fmt = KTX_COMPRESSED_RGBA_ASTC_4x4_KHR;
base_internal_fmt = KTX_RGBA;
break;
}
case cATC_RGB:
case texture_format::cATC_RGB:
{
internal_fmt = KTX_ATC_RGB_AMD;
break;
}
case cATC_RGBA_INTERPOLATED_ALPHA:
case texture_format::cATC_RGBA_INTERPOLATED_ALPHA:
{
internal_fmt = KTX_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
base_internal_fmt = KTX_RGBA;
break;
}
case texture_format::cETC2_R11_EAC:
{
internal_fmt = KTX_COMPRESSED_R11_EAC;
base_internal_fmt = KTX_RED;
break;
}
case texture_format::cETC2_RG11_EAC:
{
internal_fmt = KTX_COMPRESSED_RG11_EAC;
base_internal_fmt = KTX_RG;
break;
}
case texture_format::cFXT1_RGB:
{
internal_fmt = KTX_COMPRESSED_RGB_FXT1_3DFX;
break;
}
case texture_format::cPVRTC2_4_RGBA:
{
internal_fmt = KTX_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;
base_internal_fmt = KTX_RGBA;
break;
}
default:
{
// TODO
......@@ -1024,5 +1415,37 @@ namespace basisu
return write_compressed_texture_file(pFilename, v, false);
}
const uint32_t OUT_FILE_MAGIC = 'TEXC';
struct out_file_header
{
packed_uint<4> m_magic;
packed_uint<4> m_pad;
packed_uint<4> m_width;
packed_uint<4> m_height;
};
// As no modern tool supports FXT1 format .KTX files, let's write .OUT files and make sure 3DFX's original tools shipped in 1999 can decode our encoded output.
bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi)
{
out_file_header hdr;
hdr.m_magic = OUT_FILE_MAGIC;
hdr.m_pad = 0;
hdr.m_width = gi.get_blocks_x() * 8;
hdr.m_height = gi.get_blocks_y() * 4;
FILE* pFile = nullptr;
#ifdef _WIN32
fopen_s(&pFile, pFilename, "wb");
#else
pFile = fopen(pFilename, "wb");
#endif
if (!pFile)
return false;
fwrite(&hdr, sizeof(hdr), 1, pFile);
fwrite(gi.get_ptr(), gi.get_size_in_bytes(), 1, pFile);
return fclose(pFile) != EOF;
}
} // basisu
......@@ -37,7 +37,7 @@ namespace basisu
void clear()
{
m_fmt = cInvalidTextureFormat;
m_fmt = texture_format::cInvalidTextureFormat;
m_width = 0;
m_height = 0;
m_block_width = 0;
......@@ -101,7 +101,7 @@ namespace basisu
m_blocks.resize(m_blocks_x * m_blocks_y * m_qwords_per_block);
}
bool unpack(image& img, bool pvrtc_wrap_addressing = true) const;
bool unpack(image& img) const;
void override_dimensions(uint32_t w, uint32_t h)
{
......@@ -132,6 +132,7 @@ namespace basisu
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g);
bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi);
// GPU texture block unpacking
void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels);
......@@ -142,6 +143,9 @@ namespace basisu
bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels);
bool unpack_bc7_mode5(const void* pBlock_bits, color_rgba* pPixels);
void unpack_atc(const void* pBlock_bits, color_rgba* pPixels);
bool unpack_fxt1(const void* p, color_rgba* pPixels);
bool unpack_pvrtc2(const void* p, color_rgba* pPixels);
void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels);
// unpack_block() is only capable of unpacking texture data created by the transcoder.
// For some texture formats (like BC7, or ETC2) it's not a complete implementation.
......
......@@ -193,21 +193,12 @@ namespace basisu
int block_x1 = block_x0 + 1;
int block_y0 = (static_cast<int>(y) - 2) >> 2;
int block_y1 = block_y0 + 1;
if (m_wrap_addressing)
{
block_x0 = posmod(block_x0, m_block_width);
block_x1 = posmod(block_x1, m_block_width);
block_y0 = posmod(block_y0, m_block_height);
block_y1 = posmod(block_y1, m_block_height);
}
else
{
block_x0 = clamp<int>(block_x0, 0, m_block_width - 1);
block_x1 = clamp<int>(block_x1, 0, m_block_width - 1);
block_y0 = clamp<int>(block_y0, 0, m_block_height - 1);
block_y1 = clamp<int>(block_y1, 0, m_block_height - 1);
}
block_x0 = posmod(block_x0, m_block_width);
block_x1 = posmod(block_x1, m_block_width);
block_y0 = posmod(block_y0, m_block_height);
block_y1 = posmod(block_y1, m_block_height);
pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
......@@ -240,21 +231,12 @@ namespace basisu
int block_x1 = block_x0 + 1;
int block_y0 = (static_cast<int>(y) - 2) >> 2;
int block_y1 = block_y0 + 1;
if (m_wrap_addressing)
{
block_x0 = posmod(block_x0, m_block_width);
block_x1 = posmod(block_x1, m_block_width);
block_y0 = posmod(block_y0, m_block_height);
block_y1 = posmod(block_y1, m_block_height);
}
else
{
block_x0 = clamp<int>(block_x0, 0, m_block_width - 1);
block_x1 = clamp<int>(block_x1, 0, m_block_width - 1);
block_y0 = clamp<int>(block_y0, 0, m_block_height - 1);
block_y1 = clamp<int>(block_y1, 0, m_block_height - 1);
}
block_x0 = posmod(block_x0, m_block_width);
block_x1 = posmod(block_x1, m_block_width);
block_y0 = posmod(block_y0, m_block_height);
block_y1 = posmod(block_y1, m_block_height);
if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
{
if (m == 0)
......
......@@ -168,15 +168,14 @@ namespace basisu
{
public:
inline pvrtc4_image() :
m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_uses_alpha(false)
{
}
inline pvrtc4_image(uint32_t width, uint32_t height, bool wrap_addressing = false) :
m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
inline pvrtc4_image(uint32_t width, uint32_t height) :
m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_uses_alpha(false)
{
resize(width, height);
set_wrap_addressing(wrap_addressing);
}
inline void clear()
......@@ -187,7 +186,6 @@ namespace basisu
m_block_height = 0;
m_blocks.clear();
m_uses_alpha = false;
m_wrap_addressing = false;
}
inline void resize(uint32_t width, uint32_t height)
......@@ -218,9 +216,6 @@ namespace basisu
inline bool get_uses_alpha() const { return m_uses_alpha; }
inline void set_uses_alpha(bool uses_alpha) { m_uses_alpha = uses_alpha; }
inline void set_wrap_addressing(bool wrapping) { m_wrap_addressing = wrapping; }
inline bool get_wrap_addressing() const { return m_wrap_addressing; }
inline bool are_blocks_equal(const pvrtc4_image& rhs) const
{
return m_blocks == rhs.m_blocks;
......@@ -298,24 +293,24 @@ namespace basisu
dst(x, y) = get_pixel(block_x * 4 + x, block_y * 4 + y);
}
inline int wrap_or_clamp_x(int x) const
inline int wrap_x(int x) const
{
return m_wrap_addressing ? posmod(x, m_width) : clamp<int>(x, 0, m_width - 1);
return posmod(x, m_width);
}
inline int wrap_or_clamp_y(int y) const
inline int wrap_y(int y) const
{
return m_wrap_addressing ? posmod(y, m_height) : clamp<int>(y, 0, m_height - 1);
return posmod(y, m_height);
}
inline int wrap_or_clamp_block_x(int bx) const
inline int wrap_block_x(int bx) const
{
return m_wrap_addressing ? posmod(bx, m_block_width) : clamp<int>(bx, 0, m_block_width - 1);
return posmod(bx, m_block_width);
}
inline int wrap_or_clamp_block_y(int by) const
inline int wrap_block_y(int by) const
{
return m_wrap_addressing ? posmod(by, m_block_height) : clamp<int>(by, 0, m_block_height - 1);
return posmod(by, m_block_height);
}
inline vec2F get_interpolation_factors(uint32_t x, uint32_t y) const
......@@ -362,7 +357,6 @@ namespace basisu
pvrtc4_block_vector2D m_blocks;
uint32_t m_block_width, m_block_height;
bool m_wrap_addressing;
bool m_uses_alpha;
};
......
......@@ -27,7 +27,7 @@
using namespace basisu;
#define BASISU_TOOL_VERSION "1.09.00"
#define BASISU_TOOL_VERSION "1.10.00"
enum tool_mode
{
......@@ -35,7 +35,8 @@ enum tool_mode
cCompress,
cValidate,
cUnpack,
cCompare
cCompare,
cVersion,
};
static void print_usage()
......@@ -47,6 +48,7 @@ static void print_usage()
" -unpack: Use transcoder to unpack .basis file to one or more .ktx/.png files\n"
" -validate: Validate and display information about a .basis file\n"
" -compare: Compare two PNG images specified with -file, output PSNR and SSIM statistics and RGB/A delta images\n"
" -version: Print basisu version and exit\n"
"Unless an explicit mode is specified, if one or more files have the .basis extension this tool defaults to unpack mode.\n"
"\n"
"Important: By default, the compressor assumes the input is in the sRGB colorspace (like photos/albedo textures).\n"
......@@ -82,7 +84,7 @@ static void print_usage()
" -normal_map: Tunes codec parameters for better quality on normal maps (linear colorspace metrics, linear mipmap filtering, no selector RDO, no sRGB)\n"
" -no_alpha: Always output non-alpha basis files, even if one or more inputs has alpha\n"
" -force_alpha: Always output alpha basis files, even if no inputs has alpha\n"
" -seperate_rg_to_color_alpha: Seperate input R and G channels to RGB and A (for tangent space XY normal maps)\n"
" -separate_rg_to_color_alpha: Separate input R and G channels to RGB and A (for tangent space XY normal maps)\n"
" -no_multithreading: Disable multithreading\n"
" -no_ktx: Disable KTX writing when unpacking (faster)\n"
" -etc1_only: Only unpack to ETC1, skipping the other texture formats during -unpack\n"
......@@ -108,7 +110,7 @@ static void print_usage()
"\n"
"Hierarchical virtual selector codebook options:\n"
" -global_sel_pal: Always use vitual selector palettes (instead of custom palettes), slightly smaller files, but lower quality, slower encoding\n"
" -no_auto_global_sel_pal: Don't automatically use virtual selector palettes on small images\n"
" -auto_global_sel_pal: Automatically use virtual selector palettes on small images for slightly smaller files (defaults to off for faster encoding time)\n"
" -no_hybrid_sel_cb: Don't automatically use hybrid virtual selector codebooks (for higher quality, only active when -global_sel_pal is specified)\n"
" -global_pal_bits X: Set virtual selector codebook palette bits, range is [0,12], default is 8, higher is slower/better quality\n"
" -global_mod_bits X: Set virtual selector codebook modifier bits, range is [0,15], defualt is 8, higher is slower/better quality\n"
......@@ -216,6 +218,8 @@ static bool load_listing_file(const std::string &f, std::vector<std::string> &fi
class command_line_params
{
BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(command_line_params);
public:
command_line_params() :
m_mode(cDefault),
......@@ -248,6 +252,8 @@ public:
m_mode = cUnpack;
else if (strcasecmp(pArg, "-validate") == 0)
m_mode = cValidate;
else if (strcasecmp(pArg, "-version") == 0)
m_mode = cVersion;
else if (strcasecmp(pArg, "-compare_ssim") == 0)
m_compare_ssim = true;
else if (strcasecmp(pArg, "-file") == 0)
......@@ -347,7 +353,8 @@ public:
m_comp_params.m_check_for_alpha = false;
else if (strcasecmp(pArg, "-force_alpha") == 0)
m_comp_params.m_force_alpha = true;
else if (strcasecmp(pArg, "-seperate_rg_to_color_alpha") == 0)
else if ((strcasecmp(pArg, "-separate_rg_to_color_alpha") == 0) ||
(strcasecmp(pArg, "-seperate_rg_to_color_alpha") == 0)) // was mispelled for a while - whoops!
m_comp_params.m_seperate_rg_to_color_alpha = true;
else if (strcasecmp(pArg, "-no_multithreading") == 0)
{
......@@ -407,7 +414,9 @@ public:
else if (strcasecmp(pArg, "-global_sel_pal") == 0)
m_comp_params.m_global_sel_pal = true;
else if (strcasecmp(pArg, "-no_auto_global_sel_pal") == 0)
m_comp_params.m_no_auto_global_sel_pal = true;
m_comp_params.m_auto_global_sel_pal = false;
else if (strcasecmp(pArg, "-auto_global_sel_pal") == 0)
m_comp_params.m_auto_global_sel_pal = true;
else if (strcasecmp(pArg, "-global_pal_bits") == 0)
{
REMAINING_ARGS_CHECK(1);
......@@ -942,14 +951,14 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
printf("start_transcoding time: %3.3f ms\n", tm.get_elapsed_ms());
std::vector< gpu_image_vec > gpu_images[basist::cTFTotalTextureFormats];
std::vector< gpu_image_vec > gpu_images[(int)basist::transcoder_texture_format::cTFTotalTextureFormats];
int first_format = 0;
int last_format = basist::cTFTotalBlockTextureFormats;
int last_format = (int)basist::transcoder_texture_format::cTFTotalTextureFormats;
if (opts.m_etc1_only)
{
first_format = basist::cTFETC1;
first_format = (int)basist::transcoder_texture_format::cTFETC1_RGB;
last_format = first_format + 1;
}
......@@ -957,15 +966,23 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
{
basist::transcoder_texture_format tex_fmt = static_cast<basist::transcoder_texture_format>(format_iter);
gpu_images[tex_fmt].resize(fileinfo.m_total_images);
if (basist::basis_transcoder_format_is_uncompressed(tex_fmt))
continue;
gpu_images[(int)tex_fmt].resize(fileinfo.m_total_images);
for (uint32_t image_index = 0; image_index < fileinfo.m_total_images; image_index++)
gpu_images[tex_fmt][image_index].resize(fileinfo.m_image_mipmap_levels[image_index]);
gpu_images[(int)tex_fmt][image_index].resize(fileinfo.m_image_mipmap_levels[image_index]);
}
// Now transcode the file to all supported texture formats and save mipmapped KTX files
for (int format_iter = first_format; format_iter < last_format; format_iter++)
{
const basist::transcoder_texture_format transcoder_tex_fmt = static_cast<basist::transcoder_texture_format>(format_iter);
if (basist::basis_transcoder_format_is_uncompressed(transcoder_tex_fmt))
continue;
for (uint32_t image_index = 0; image_index < fileinfo.m_total_images; image_index++)
{
for (uint32_t level_index = 0; level_index < fileinfo.m_image_mipmap_levels[image_index]; level_index++)
......@@ -977,10 +994,8 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
error_printf("Failed retrieving image level information (%u %u)!\n", image_index, level_index);
return false;
}
const basist::transcoder_texture_format transcoder_tex_fmt = static_cast<basist::transcoder_texture_format>(format_iter);
if ((transcoder_tex_fmt == basist::cTFPVRTC1_4_RGB) || (transcoder_tex_fmt == basist::cTFPVRTC1_4_RGBA))
if ((transcoder_tex_fmt == basist::transcoder_texture_format::cTFPVRTC1_4_RGB) || (transcoder_tex_fmt == basist::transcoder_texture_format::cTFPVRTC1_4_RGBA))
{
if (!is_pow2(level_info.m_width) || !is_pow2(level_info.m_height))
{
......@@ -995,52 +1010,24 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
basisu::texture_format tex_fmt = basis_get_basisu_texture_format(transcoder_tex_fmt);
gpu_image& gi = gpu_images[transcoder_tex_fmt][image_index][level_index];
gpu_image& gi = gpu_images[(int)transcoder_tex_fmt][image_index][level_index];
gi.init(tex_fmt, level_info.m_orig_width, level_info.m_orig_height);
// Fill the buffer with psuedo-random bytes, to help more visibly detect cases where the transcoder fails to write to part of the output.
fill_buffer_with_random_bytes(gi.get_ptr(), gi.get_size_in_bytes());
tm.start();
#if 1
if (!dec.transcode_image_level(&basis_data[0], (uint32_t)basis_data.size(), image_index, level_index, gi.get_ptr(), gi.get_total_blocks(), transcoder_tex_fmt, 0))
{
error_printf("Failed transcoding image level (%u %u %u)!\n", image_index, level_index, format_iter);
return false;
}
double total_transcode_time = tm.get_elapsed_ms();
#else
// quick and dirty row pitch parameter test, to be moved into a unit test
uint8_vec temp;
uint32_t block_pitch_to_test = level_info.m_num_blocks_x;
if ((transcoder_tex_fmt != basist::cTFPVRTC1_4_RGB) || (transcoder_tex_fmt != basist::cTFPVRTC1_4_RGBA))
block_pitch_to_test += 5;
temp.resize(level_info.m_num_blocks_y * block_pitch_to_test * gi.get_bytes_per_block());
fill_buffer_with_random_bytes(&temp[0], temp.size());
uint32_t decode_flags = 0;
tm.start();
if (!dec.transcode_image_level(&basis_data[0], (uint32_t)basis_data.size(), image_index, level_index, &temp[0], (uint32_t)(temp.size() / gi.get_bytes_per_block()), transcoder_tex_fmt, 0, block_pitch_to_test))
if (!dec.transcode_image_level(&basis_data[0], (uint32_t)basis_data.size(), image_index, level_index, gi.get_ptr(), gi.get_total_blocks(), transcoder_tex_fmt, decode_flags))
{
error_printf("Failed transcoding image level (%u %u %u)!\n", image_index, level_index, format_iter);
return false;
}
double total_transcode_time = tm.get_elapsed_ms();
if ((transcoder_tex_fmt == basist::cTFPVRTC1_4_RGB) || (transcoder_tex_fmt == basist::cTFPVRTC1_4_RGBA))
{
assert(temp.size() == gi.get_size_in_bytes());
memcpy(gi.get_ptr(), &temp[0], gi.get_size_in_bytes());
}
else
{
for (uint32_t y = 0; y < level_info.m_num_blocks_y; y++)
memcpy(gi.get_block_ptr(0, y), &temp[y * block_pitch_to_test * gi.get_bytes_per_block()], gi.get_row_pitch_in_bytes());
}
#endif
printf("Transcode of image %u level %u res %ux%u format %s succeeded in %3.3f ms\n", image_index, level_index, level_info.m_orig_width, level_info.m_orig_height, basist::basis_get_format_name(transcoder_tex_fmt), total_transcode_time);
} // format_iter
......@@ -1057,6 +1044,9 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
{
const basist::transcoder_texture_format transcoder_tex_fmt = static_cast<basist::transcoder_texture_format>(format_iter);
if (basist::basis_transcoder_format_is_uncompressed(transcoder_tex_fmt))
continue;
if ((!opts.m_no_ktx) && (fileinfo.m_tex_type == basist::cBASISTexTypeCubemapArray))
{
// No KTX tool that we know of supports cubemap arrays, so write individual cubemap files.
......@@ -1132,6 +1122,21 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
}
printf("Wrote PNG file \"%s\"\n", rgb_filename.c_str());
if (transcoder_tex_fmt == basist::transcoder_texture_format::cTFFXT1_RGB)
{
std::string out_filename;
if (gi.size() > 1)
out_filename = base_filename + string_format("_unpacked_rgb_%s_%u_%04u.out", basist::basis_get_format_name(transcoder_tex_fmt), level_index, image_index);
else
out_filename = base_filename + string_format("_unpacked_rgb_%s_%04u.out", basist::basis_get_format_name(transcoder_tex_fmt), image_index);
if (!write_3dfx_out_file(out_filename.c_str(), gi[level_index]))
{
error_printf("Failed writing to OUT file \"%s\"\n", out_filename.c_str());
return false;
}
printf("Wrote .OUT file \"%s\"\n", out_filename.c_str());
}
if (basis_transcoder_format_has_alpha(transcoder_tex_fmt))
{
std::string a_filename;
......@@ -1160,7 +1165,7 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
{
for (uint32_t level_index = 0; level_index < fileinfo.m_image_mipmap_levels[image_index]; level_index++)
{
const basist::transcoder_texture_format transcoder_tex_fmt = basist::cTFRGBA32;
const basist::transcoder_texture_format transcoder_tex_fmt = basist::transcoder_texture_format::cTFRGBA32;
basist::basisu_image_level_info level_info;
......@@ -1210,7 +1215,7 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
{
for (uint32_t level_index = 0; level_index < fileinfo.m_image_mipmap_levels[image_index]; level_index++)
{
const basist::transcoder_texture_format transcoder_tex_fmt = basist::cTFRGB565;
const basist::transcoder_texture_format transcoder_tex_fmt = basist::transcoder_texture_format::cTFRGB565;
basist::basisu_image_level_info level_info;
......@@ -1258,14 +1263,6 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
}
printf("Wrote PNG file \"%s\"\n", rgb_filename.c_str());
std::string a_filename(base_filename + string_format("_unpacked_a_%s_%u_%04u.png", basist::basis_get_format_name(transcoder_tex_fmt), level_index, image_index));
if (!save_png(a_filename, img, cImageSaveGrayscale, 3))
{
error_printf("Failed writing to PNG file \"%s\"\n", a_filename.c_str());
return false;
}
printf("Wrote PNG file \"%s\"\n", a_filename.c_str());
} // level_index
} // image_index
......@@ -1274,7 +1271,7 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
{
for (uint32_t level_index = 0; level_index < fileinfo.m_image_mipmap_levels[image_index]; level_index++)
{
const basist::transcoder_texture_format transcoder_tex_fmt = basist::cTFRGBA4444;
const basist::transcoder_texture_format transcoder_tex_fmt = basist::transcoder_texture_format::cTFRGBA4444;
basist::basisu_image_level_info level_info;
......@@ -1515,6 +1512,9 @@ static int main_internal(int argc, const char **argv)
case cCompare:
status = compare_mode(opts);
break;
case cVersion:
status = true; // We printed the version at the beginning of main_internal
break;
default:
assert(0);
break;
......
......@@ -301,7 +301,7 @@ namespace basisu
// GPU texture formats
enum texture_format
enum class texture_format
{
cInvalidTextureFormat = -1,
......@@ -321,6 +321,10 @@ namespace basisu
cPVRTC1_4_RGBA,
cATC_RGB,
cATC_RGBA_INTERPOLATED_ALPHA,
cFXT1_RGB,
cPVRTC2_4_RGBA,
cETC2_R11_EAC,
cETC2_RG11_EAC,
// Uncompressed/raw pixels
cRGBA32,
......@@ -334,17 +338,19 @@ namespace basisu
{
switch (fmt)
{
case cETC1:
case cETC1S:
case cETC2_RGB:
case cETC2_ALPHA:
case cBC1:
case cBC4:
case cPVRTC1_4_RGB:
case cPVRTC1_4_RGBA:
case cATC_RGB:
case texture_format::cETC1:
case texture_format::cETC1S:
case texture_format::cETC2_RGB:
case texture_format::cETC2_ALPHA:
case texture_format::cBC1:
case texture_format::cBC4:
case texture_format::cPVRTC1_4_RGB:
case texture_format::cPVRTC1_4_RGBA:
case texture_format::cATC_RGB:
case texture_format::cPVRTC2_4_RGBA:
case texture_format::cETC2_R11_EAC:
return 8;
case cRGBA32:
case texture_format::cRGBA32:
return sizeof(uint32_t) * 16;
default:
break;
......@@ -360,6 +366,13 @@ namespace basisu
inline uint32_t get_block_width(texture_format fmt)
{
BASISU_NOTE_UNUSED(fmt);
switch (fmt)
{
case texture_format::cFXT1_RGB:
return 8;
default:
break;
}
return 4;
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -31,42 +31,64 @@ namespace basist
// fully opaque (255) alpha channel.
// - The PVRTC1 texture formats only support power of 2 dimension .basis files, but this may be relaxed in a future version.
// - The PVRTC1 transcoders are real-time encoders, so don't expect the highest quality. We may add a slower encoder with improved quality.
enum transcoder_texture_format
// - These enums must be kept in sync with Javascript code that calls the transcoder.
enum class transcoder_texture_format
{
// Compressed formats
// ETC1-2
cTFETC1, // Opaque only, returns RGB or alpha data if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFETC2, // Opaque+alpha, ETC2_EAC_A8 block followed by a ETC1 block, alpha channel will be opaque for opaque .basis files
// BC1-5, BC7
cTFBC1, // Opaque only, no punchthrough alpha support yet, transcodes alpha slice if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC3, // Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
cTFBC4, // Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC5, // XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
cTFBC7_M6_OPAQUE_ONLY, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
cTFBC7_M5, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
// PVRTC1 4bpp
cTFPVRTC1_4_RGB, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
cTFPVRTC1_4_RGBA, // Opaque+alpha, most useful for simple opacity maps. If .basis file doens't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
// ASTC
cTFASTC_4x4, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
// ATC
cTFATC_RGB, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD)
cTFATC_RGBA_INTERPOLATED_ALPHA, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (ATC_RGBA_INTERPOLATED_ALPHA_AMD)
cTFTotalBlockTextureFormats,
cTFETC1_RGB = 0, // Opaque only, returns RGB or alpha data if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFETC2_RGBA = 1, // Opaque+alpha, ETC2_EAC_A8 block followed by a ETC1 block, alpha channel will be opaque for opaque .basis files
// BC1-5, BC7 (desktop, some mobile devices)
cTFBC1_RGB = 2, // Opaque only, no punchthrough alpha support yet, transcodes alpha slice if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC3_RGBA = 3, // Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
cTFBC4_R = 4, // Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC5_RG = 5, // XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
cTFBC7_M6_RGB = 6, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
cTFBC7_M5_RGBA = 7, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
// PVRTC1 4bpp (mobile, PowerVR devices)
cTFPVRTC1_4_RGB = 8, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doens't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
// ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
cTFASTC_4x4_RGBA = 10, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
// ATC (mobile, Adreno devices, this is a niche format)
cTFATC_RGB = 11, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD)
cTFATC_RGBA = 12, // Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD)
// FXT1 (desktop, Intel devices, this is a super obscure format)
cTFFXT1_RGB = 17, // Opaque only, uses exclusively CC_MIXED blocks. Notable for having a 8x4 block size. GL_3DFX_texture_compression_FXT1 is supported on Intel integrated GPU's (such as HD 630).
// Punch-through alpha is relatively easy to support, but full alpha is harder. This format is only here for completeness so opaque-only is fine for now.
// See the BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING macro in basisu_transcoder_internal.h.
cTFPVRTC2_4_RGB = 18, // Opaque-only, almost BC1 quality, much faster to transcode and supports arbitrary texture dimensions (unlike PVRTC1 RGB).
cTFPVRTC2_4_RGBA = 19, // Opaque+alpha, slower to encode than cTFPVRTC2_4_RGB. Premultiplied alpha is highly recommended, otherwise the color channel can leak into the alpha channel on transparent blocks.
cTFETC2_EAC_R11 = 20, // R only (ETC2 EAC R11 unsigned)
cTFETC2_EAC_RG11 = 21, // RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
// Uncompressed (raw pixel) formats
cTFRGBA32 = cTFTotalBlockTextureFormats, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
cTFRGB565, // 166pp RGB image stored in raster (not block) order in memory, R at bit position 11
cTFBGR565, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
cTFRGBA4444, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
cTFTotalTextureFormats
cTFRGBA32 = 13, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
cTFRGB565 = 14, // 166pp RGB image stored in raster (not block) order in memory, R at bit position 11
cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
cTFTotalTextureFormats = 22,
// Old enums for compatibility with code compiled against previous versions
cTFETC1 = cTFETC1_RGB,
cTFETC2 = cTFETC2_RGBA,
cTFBC1 = cTFBC1_RGB,
cTFBC3 = cTFBC3_RGBA,
cTFBC4 = cTFBC4_R,
cTFBC5 = cTFBC5_RG,
cTFBC7_M6_OPAQUE_ONLY = cTFBC7_M6_RGB,
cTFBC7_M5 = cTFBC7_M5_RGBA,
cTFASTC_4x4 = cTFASTC_4x4_RGBA,
cTFATC_RGBA_INTERPOLATED_ALPHA = cTFATC_RGBA,
};
uint32_t basis_get_bytes_per_block(transcoder_texture_format fmt);
......@@ -74,10 +96,16 @@ namespace basist
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt);
basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt);
const char* basis_get_texture_type_name(basis_texture_type tex_type);
bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type);
bool basis_block_format_is_uncompressed(block_format tex_type);
uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt);
uint32_t basis_get_block_width(transcoder_texture_format tex_type);
uint32_t basis_get_block_height(transcoder_texture_format tex_type);
// Returns true if the specified format was enabled at compile time.
bool basis_is_format_supported(transcoder_texture_format tex_type);
class basisu_transcoder;
// This struct holds all state used during transcoding. For video, it needs to persist between image transcodes (it holds the previous frame).
......@@ -111,7 +139,7 @@ namespace basist
bool decode_tables(const uint8_t *pTable_data, uint32_t table_data_size);
bool transcode_slice(void *pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t *pImage_data, uint32_t image_data_size, block_format fmt,
uint32_t output_block_or_pixel_stride_in_bytes, bool wrap_addressing, bool bc1_allow_threecolor_blocks, const basis_file_header &header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header &header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
basisu_transcoder_state *pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
private:
......@@ -276,9 +304,6 @@ namespace basist
enum
{
// PVRTC1: texture will use wrap addressing vs. clamp (most PVRTC viewer tools assume wrap addressing, so we default to wrap although that can cause edge artifacts)
cDecodeFlagsPVRTCWrapAddressing = 1,
// PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
cDecodeFlagsPVRTCDecodeToNextPow2 = 2,
......@@ -292,7 +317,7 @@ namespace basist
// The output buffer contains alpha endpoint/selector indices.
// Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
cDecodeFlagsOutputHasAlphaIndices = 16,
cDecodeFlagsOutputHasAlphaIndices = 16
};
// transcode_image_level() decodes a single mipmap level from the .basis file to any of the supported output texture formats.
......@@ -311,7 +336,7 @@ namespace basist
uint32_t image_index, uint32_t level_index,
void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
transcoder_texture_format fmt,
uint32_t decode_flags = cDecodeFlagsPVRTCWrapAddressing, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state *pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state *pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
// Finds the basis slice corresponding to the specified image/level/alpha params, or -1 if the slice can't be found.
int find_slice(const void *pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const;
......@@ -327,7 +352,7 @@ namespace basist
// - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function.
bool transcode_slice(const void *pData, uint32_t data_size, uint32_t slice_index,
void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = cDecodeFlagsPVRTCWrapAddressing, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state * pState = nullptr, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0) const;
block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state * pState = nullptr, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0) const;
private:
mutable basisu_lowlevel_transcoder m_lowlevel_decoder;
......
......@@ -42,7 +42,7 @@ namespace basist
{
// Low-level formats directly supported by the transcoder (other supported texture formats are combinations of these low-level block formats).
// You probably don't care about these enum's unless you are going pretty low-level and calling the transcoder to decode individual slices.
enum block_format
enum class block_format
{
cETC1, // ETC1S RGB
cBC1, // DXT1 RGB
......@@ -57,6 +57,7 @@ namespace basist
// data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking.
cATC_RGB,
cATC_RGBA_INTERPOLATED_ALPHA,
cFXT1_RGB, // Opaque-only, has oddball 8x4 pixel block size
cIndices, // Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits)
......@@ -71,6 +72,11 @@ namespace basist
cRGBA4444_ALPHA,
cRGBA4444_COLOR_OPAQUE,
cPVRTC2_4_RGB,
cPVRTC2_4_RGBA,
cETC2_EAC_R11,
cTotalBlockFormats
};
......@@ -624,6 +630,11 @@ namespace basist
struct decoder_etc_block;
inline uint8_t clamp255(int32_t i)
{
return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i);
}
struct color32
{
union
......@@ -647,6 +658,8 @@ namespace basist
void set(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { c[0] = static_cast<uint8_t>(vr); c[1] = static_cast<uint8_t>(vg); c[2] = static_cast<uint8_t>(vb); c[3] = static_cast<uint8_t>(va); }
void set_clamped(int vr, int vg, int vb, int va) { c[0] = clamp255(vr); c[1] = clamp255(vg); c[2] = clamp255(vb); c[3] = clamp255(va); }
uint8_t operator[] (uint32_t idx) const { assert(idx < 4); return c[idx]; }
uint8_t &operator[] (uint32_t idx) { assert(idx < 4); return c[idx]; }
......@@ -733,6 +746,8 @@ namespace basist
}
};
bool basis_block_format_is_uncompressed(block_format tex_type);
} // namespace basist
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment