mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-06-08 00:23:52 +00:00
Important: Changing the Basis file version, so any existing files will need to be recompressed!
Adding new fields to the basis header: texture type and framerate. Texture type may be 2D, 2D array, video, volume, or cubemap array. The compressor makes sure that anything other than pure 2D follows certain constraints (cubemap arrays must have a multiple of 6 input images, videos/texture array images all must have the same resolution/# of mipmaps, etc.) When unpacking cubemaps, the -unpack command now writes cubemap .KTX files which various tools like PVRTexTool support.
This commit is contained in:
@@ -122,7 +122,7 @@ namespace basisu
|
||||
uint32_t m_num_macroblocks_x;
|
||||
uint32_t m_num_macroblocks_y;
|
||||
|
||||
uint32_t m_source_file_index;
|
||||
uint32_t m_source_file_index; // also the basis image index
|
||||
uint32_t m_mip_index;
|
||||
bool m_alpha;
|
||||
};
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
#include "transcoder/basisu_transcoder.h"
|
||||
|
||||
// The output file version. Keep in sync with BASISD_SUPPORTED_BASIS_VERSION.
|
||||
#define BASIS_FILE_VERSION (0x11)
|
||||
#define BASIS_FILE_VERSION (0x12)
|
||||
|
||||
namespace basisu
|
||||
{
|
||||
void basisu_file::create_header(const basisu_backend_output &encoder_output, uint32_t userdata0, uint32_t userdata1, bool y_flipped)
|
||||
void basisu_file::create_header(const basisu_backend_output &encoder_output, basist::basis_texture_type tex_type, uint32_t userdata0, uint32_t userdata1, bool y_flipped, uint32_t us_per_frame)
|
||||
{
|
||||
m_header.m_header_size = sizeof(basist::basis_file_header);
|
||||
|
||||
@@ -34,13 +34,13 @@ namespace basisu
|
||||
|
||||
m_header.m_format = basist::cETC1;
|
||||
m_header.m_flags = 0;
|
||||
|
||||
|
||||
if (encoder_output.m_etc1s)
|
||||
m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagETC1S;
|
||||
|
||||
if (y_flipped)
|
||||
m_header.m_flags = m_header.m_flags | basist::cBASISHeaderFlagYFlipped;
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < encoder_output.m_slice_desc.size(); i++)
|
||||
{
|
||||
if (encoder_output.m_slice_desc[i].m_alpha)
|
||||
@@ -50,6 +50,9 @@ namespace basisu
|
||||
}
|
||||
}
|
||||
|
||||
m_header.m_tex_type = static_cast<uint8_t>(tex_type);
|
||||
m_header.m_us_per_frame = clamp<uint32_t>(us_per_frame, 0, basist::cBASISMaxUSPerFrame);
|
||||
|
||||
m_header.m_userdata0 = userdata0;
|
||||
m_header.m_userdata1 = userdata1;
|
||||
|
||||
@@ -151,7 +154,7 @@ namespace basisu
|
||||
pHeader->m_ver = BASIS_FILE_VERSION;// basist::basis_file_header::cBASISFirstVersion;
|
||||
}
|
||||
|
||||
bool basisu_file::init(const basisu_backend_output &encoder_output, uint32_t userdata0, uint32_t userdata1, bool y_flipped)
|
||||
bool basisu_file::init(const basisu_backend_output &encoder_output, basist::basis_texture_type tex_type, uint32_t userdata0, uint32_t userdata1, bool y_flipped, uint32_t us_per_frame)
|
||||
{
|
||||
clear();
|
||||
|
||||
@@ -184,7 +187,7 @@ namespace basisu
|
||||
|
||||
m_total_file_size = (uint32_t)total_file_size;
|
||||
|
||||
create_header(encoder_output, userdata0, userdata1, y_flipped);
|
||||
create_header(encoder_output, tex_type, userdata0, userdata1, y_flipped, us_per_frame);
|
||||
|
||||
if (!create_image_descs(encoder_output))
|
||||
return false;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace basisu
|
||||
m_total_file_size = 0;
|
||||
}
|
||||
|
||||
bool init(const basisu_backend_output& encoder_output, uint32_t userdata0 = 0, uint32_t userdata1 = 0, bool y_flipped = false);
|
||||
bool init(const basisu_backend_output& encoder_output, basist::basis_texture_type tex_type, uint32_t userdata0, uint32_t userdata1, bool y_flipped, uint32_t us_per_frame);
|
||||
|
||||
const uint8_vec &get_compressed_data() const { return m_comp_data; }
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace basisu
|
||||
uint32_t m_first_image_file_ofs;
|
||||
uint32_t m_total_file_size;
|
||||
|
||||
void create_header(const basisu_backend_output& encoder_output, uint32_t userdata0, uint32_t userdata1, bool y_flipped);
|
||||
void create_header(const basisu_backend_output& encoder_output, basist::basis_texture_type tex_type, uint32_t userdata0, uint32_t userdata1, bool y_flipped, uint32_t us_per_frame);
|
||||
bool create_image_descs(const basisu_backend_output& encoder_output);
|
||||
void create_comp_data(const basisu_backend_output& encoder_output);
|
||||
void fixup_crcs();
|
||||
|
||||
126
basisu_comp.cpp
126
basisu_comp.cpp
@@ -88,6 +88,10 @@ namespace basisu
|
||||
debug_printf("m_max_endpoint_clusters: %u\n", m_params.m_max_endpoint_clusters);
|
||||
debug_printf("m_max_selector_clusters: %u\n", m_params.m_max_selector_clusters);
|
||||
debug_printf("m_quality_level: %i\n", m_params.m_quality_level);
|
||||
|
||||
debug_printf("m_tex_type: %u\n", m_params.m_tex_type);
|
||||
debug_printf("m_userdata0: 0x%X, m_userdata1: 0x%X\n", m_params.m_userdata0, m_params.m_userdata1);
|
||||
debug_printf("m_us_per_frame: %i (%f fps)\n", m_params.m_us_per_frame, m_params.m_us_per_frame ? 1.0f / (m_params.m_us_per_frame / 1000000.0f) : 0);
|
||||
|
||||
#undef PRINT_BOOL_VALUE
|
||||
#undef PRINT_INT_VALUE
|
||||
@@ -111,6 +115,9 @@ namespace basisu
|
||||
if (!read_source_images())
|
||||
return cECFailedReadingSourceImages;
|
||||
|
||||
if (!validate_texture_type_constraints())
|
||||
return cECFailedValidating;
|
||||
|
||||
if (!process_frontend())
|
||||
return cECFailedFrontEnd;
|
||||
|
||||
@@ -214,7 +221,7 @@ namespace basisu
|
||||
|
||||
m_stats.resize(0);
|
||||
m_slice_descs.resize(0);
|
||||
m_source_images.resize(0);
|
||||
m_slice_images.resize(0);
|
||||
|
||||
m_total_blocks = 0;
|
||||
uint32_t total_macroblocks = 0;
|
||||
@@ -389,20 +396,20 @@ namespace basisu
|
||||
{
|
||||
const bool is_alpha_slice = m_any_source_image_has_alpha && ((slice_index & 1) != 0);
|
||||
|
||||
image &source_image = slices[slice_index];
|
||||
const uint32_t orig_width = source_image.get_width();
|
||||
const uint32_t orig_height = source_image.get_height();
|
||||
image &slice_image = slices[slice_index];
|
||||
const uint32_t orig_width = slice_image.get_width();
|
||||
const uint32_t orig_height = slice_image.get_height();
|
||||
|
||||
// Enlarge the source image to 4x4 block boundaries, duplicating edge pixels if necessary to avoid introducing extra colors into blocks.
|
||||
source_image.crop_dup_borders(source_image.get_block_width(4) * 4, source_image.get_block_height(4) * 4);
|
||||
slice_image.crop_dup_borders(slice_image.get_block_width(4) * 4, slice_image.get_block_height(4) * 4);
|
||||
|
||||
if (m_params.m_debug_images)
|
||||
{
|
||||
save_png(string_format("basis_debug_source_image_%u_%u.png", source_file_index, slice_index).c_str(), source_image);
|
||||
save_png(string_format("basis_debug_source_image_%u_%u.png", source_file_index, slice_index).c_str(), slice_image);
|
||||
}
|
||||
|
||||
enlarge_vector(m_stats, 1);
|
||||
enlarge_vector(m_source_images, 1);
|
||||
enlarge_vector(m_slice_images, 1);
|
||||
enlarge_vector(m_slice_descs, 1);
|
||||
|
||||
const uint32_t dest_image_index = (uint32_t)m_stats.size() - 1;
|
||||
@@ -411,9 +418,9 @@ namespace basisu
|
||||
m_stats[dest_image_index].m_width = orig_width;
|
||||
m_stats[dest_image_index].m_height = orig_height;
|
||||
|
||||
m_source_images[dest_image_index] = source_image;
|
||||
m_slice_images[dest_image_index] = slice_image;
|
||||
|
||||
debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), orig_width, orig_height, source_image.get_width(), source_image.get_height());
|
||||
debug_printf("****** Slice %u: mip %u, alpha_slice: %u, filename: \"%s\", original: %ux%u actual: %ux%u\n", m_slice_descs.size() - 1, mip_indices[slice_index], is_alpha_slice, source_filename.c_str(), orig_width, orig_height, slice_image.get_width(), slice_image.get_height());
|
||||
|
||||
basisu_backend_slice_desc &slice_desc = m_slice_descs[dest_image_index];
|
||||
|
||||
@@ -422,11 +429,11 @@ namespace basisu
|
||||
slice_desc.m_orig_width = orig_width;
|
||||
slice_desc.m_orig_height = orig_height;
|
||||
|
||||
slice_desc.m_width = source_image.get_width();
|
||||
slice_desc.m_height = source_image.get_height();
|
||||
slice_desc.m_width = slice_image.get_width();
|
||||
slice_desc.m_height = slice_image.get_height();
|
||||
|
||||
slice_desc.m_num_blocks_x = source_image.get_block_width(4);
|
||||
slice_desc.m_num_blocks_y = source_image.get_block_height(4);
|
||||
slice_desc.m_num_blocks_x = slice_image.get_block_width(4);
|
||||
slice_desc.m_num_blocks_y = slice_image.get_block_height(4);
|
||||
|
||||
slice_desc.m_num_macroblocks_x = (slice_desc.m_num_blocks_x + 1) >> 1;
|
||||
slice_desc.m_num_macroblocks_y = (slice_desc.m_num_blocks_y + 1) >> 1;
|
||||
@@ -519,20 +526,85 @@ namespace basisu
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do some basic validation for 2D arrays, cubemaps, video, and volumes.
|
||||
bool basis_compressor::validate_texture_type_constraints()
|
||||
{
|
||||
debug_printf("basis_compressor::validate_texture_type_constraints\n");
|
||||
|
||||
// In 2D mode anything goes (each image may have a different resolution and # of mipmap levels).
|
||||
if (m_params.m_tex_type == basist::cBASISTexType2D)
|
||||
return true;
|
||||
|
||||
uint32_t total_basis_images = 0;
|
||||
|
||||
for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
|
||||
{
|
||||
const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
|
||||
|
||||
total_basis_images = maximum<uint32_t>(total_basis_images, slice_desc.m_source_file_index + 1);
|
||||
}
|
||||
|
||||
if (m_params.m_tex_type == basist::cBASISTexTypeCubemapArray)
|
||||
{
|
||||
// For cubemaps, validate that the total # of Basis images is a multiple of 6.
|
||||
if ((total_basis_images % 6) != 0)
|
||||
{
|
||||
error_printf("basis_compressor::validate_texture_type_constraints: For cubemaps the total number of input images is not a multiple of 6!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now validate that all the mip0's have the same dimensions, and that each image has the same # of mipmap levels.
|
||||
uint_vec image_mipmap_levels(total_basis_images);
|
||||
|
||||
int width = -1, height = -1;
|
||||
for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
|
||||
{
|
||||
const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
|
||||
|
||||
image_mipmap_levels[slice_desc.m_source_file_index] = maximum(image_mipmap_levels[slice_desc.m_source_file_index], slice_desc.m_mip_index + 1);
|
||||
|
||||
if (slice_desc.m_mip_index != 0)
|
||||
continue;
|
||||
|
||||
if (width < 0)
|
||||
{
|
||||
width = slice_desc.m_orig_width;
|
||||
height = slice_desc.m_orig_height;
|
||||
}
|
||||
else if ((width != (int)slice_desc.m_orig_width) || (height != (int)slice_desc.m_orig_height))
|
||||
{
|
||||
error_printf("basis_compressor::validate_texture_type_constraints: The source image resolutions are not all equal!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < image_mipmap_levels.size(); i++)
|
||||
{
|
||||
if (image_mipmap_levels[0] != image_mipmap_levels[i])
|
||||
{
|
||||
error_printf("basis_compressor::validate_texture_type_constraints: Each image must have the same number of mipmap levels!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool basis_compressor::process_frontend()
|
||||
{
|
||||
debug_printf("basis_compressor::process_frontend\n");
|
||||
|
||||
|
||||
m_source_blocks.resize(m_total_blocks);
|
||||
|
||||
for (uint32_t slice_index = 0; slice_index < m_source_images.size(); slice_index++)
|
||||
|
||||
for (uint32_t slice_index = 0; slice_index < m_slice_images.size(); slice_index++)
|
||||
{
|
||||
const basisu_backend_slice_desc &slice_desc = m_slice_descs[slice_index];
|
||||
|
||||
const uint32_t num_blocks_x = slice_desc.m_num_blocks_x;
|
||||
const uint32_t num_blocks_y = slice_desc.m_num_blocks_y;
|
||||
|
||||
const image &source_image = m_source_images[slice_index];
|
||||
const image &source_image = m_slice_images[slice_index];
|
||||
|
||||
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++)
|
||||
@@ -800,7 +872,7 @@ namespace basisu
|
||||
|
||||
const basisu_backend_output &encoded_output = m_backend.get_output();
|
||||
|
||||
if (!m_basis_file.init(encoded_output, 0, 0, m_params.m_y_flip))
|
||||
if (!m_basis_file.init(encoded_output, m_params.m_tex_type, m_params.m_userdata0, m_params.m_userdata1, m_params.m_y_flip, m_params.m_us_per_frame))
|
||||
{
|
||||
error_printf("basis_compressor::write_output_files_and_compute_stats: basisu_backend:init() failed!\n");
|
||||
return false;
|
||||
@@ -971,37 +1043,37 @@ namespace basisu
|
||||
image_metrics em;
|
||||
|
||||
// best possible ETC1S stats
|
||||
em.calc(m_source_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0);
|
||||
em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 0);
|
||||
em.print("Unquantized ETC1S Luma: ");
|
||||
|
||||
s.m_best_luma_psnr = static_cast<float>(em.m_psnr);
|
||||
s.m_best_luma_ssim = static_cast<float>(em.m_ssim);
|
||||
|
||||
em.calc(m_source_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 3);
|
||||
em.calc(m_slice_images[slice_index], m_best_etc1s_images_unpacked[slice_index], 0, 3);
|
||||
em.print("Unquantized ETC1S RGB Avg: ");
|
||||
|
||||
s.m_best_rgb_avg_psnr = static_cast<float>(em.m_psnr);
|
||||
|
||||
// .basis ETC1S stats
|
||||
em.calc(m_source_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0);
|
||||
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 0);
|
||||
em.print(".basis ETC1S Luma: ");
|
||||
|
||||
s.m_basis_etc1_luma_psnr = static_cast<float>(em.m_psnr);
|
||||
s.m_basis_etc1_luma_ssim = static_cast<float>(em.m_ssim);
|
||||
|
||||
em.calc(m_source_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 3);
|
||||
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked[slice_index], 0, 3);
|
||||
em.print(".basis ETC1S RGB Avg: ");
|
||||
|
||||
//debug_printf(".basis ETC1 Luma SSIM per bit/texel*1000: %3.3f\n", 1000.0f * s.m_basis_etc1_luma_ssim / ((m_backend.get_output().get_output_size_estimate() * 8.0f) / (slice_desc.m_orig_width * slice_desc.m_orig_height)));
|
||||
|
||||
// .basis BC1 stats
|
||||
em.calc(m_source_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 0);
|
||||
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 0);
|
||||
em.print(".basis BC1 Luma: ");
|
||||
|
||||
s.m_basis_bc1_luma_psnr = static_cast<float>(em.m_psnr);
|
||||
s.m_basis_bc1_luma_ssim = static_cast<float>(em.m_ssim);
|
||||
|
||||
em.calc(m_source_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 3);
|
||||
em.calc(m_slice_images[slice_index], m_decoded_output_textures_unpacked_bc1[slice_index], 0, 3);
|
||||
em.print(".basis BC1 RGB Avg: ");
|
||||
|
||||
s.m_basis_bc1_rgb_avg_psnr = static_cast<float>(em.m_psnr);
|
||||
@@ -1022,7 +1094,7 @@ namespace basisu
|
||||
{
|
||||
gpu_image best_etc1s_gpu_image(m_best_etc1s_images[slice_index]);
|
||||
best_etc1s_gpu_image.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
|
||||
write_compressed_texture_file(out_basename + "_best_etc1s.ktx", best_etc1s_gpu_image);
|
||||
write_compressed_texture_file((out_basename + "_best_etc1s.ktx").c_str(), best_etc1s_gpu_image);
|
||||
|
||||
image best_etc1s_unpacked;
|
||||
best_etc1s_gpu_image.unpack(best_etc1s_unpacked);
|
||||
@@ -1033,7 +1105,7 @@ namespace basisu
|
||||
{
|
||||
gpu_image decoded_etc1s(m_decoded_output_textures[slice_index]);
|
||||
decoded_etc1s.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
|
||||
write_compressed_texture_file(out_basename + "_decoded_etc1s.ktx", decoded_etc1s);
|
||||
write_compressed_texture_file((out_basename + "_decoded_etc1s.ktx").c_str(), decoded_etc1s);
|
||||
|
||||
image temp(m_decoded_output_textures_unpacked[slice_index]);
|
||||
temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
|
||||
@@ -1044,7 +1116,7 @@ namespace basisu
|
||||
{
|
||||
gpu_image decoded_bc1(m_decoded_output_textures_bc1[slice_index]);
|
||||
decoded_bc1.override_dimensions(slice_desc.m_orig_width, slice_desc.m_orig_height);
|
||||
write_compressed_texture_file(out_basename + "_decoded_bc1.ktx", decoded_bc1);
|
||||
write_compressed_texture_file((out_basename + "_decoded_bc1.ktx").c_str(), decoded_bc1);
|
||||
|
||||
image temp(m_decoded_output_textures_unpacked_bc1[slice_index]);
|
||||
temp.crop(slice_desc.m_orig_width, slice_desc.m_orig_height);
|
||||
|
||||
@@ -231,6 +231,11 @@ namespace basisu
|
||||
m_max_endpoint_clusters = 0;
|
||||
m_max_selector_clusters = 0;
|
||||
m_quality_level = -1;
|
||||
|
||||
m_tex_type = basist::cBASISTexType2D;
|
||||
m_userdata0 = 0;
|
||||
m_userdata1 = 0;
|
||||
m_us_per_frame = 0;
|
||||
}
|
||||
|
||||
// Pointer to the global selector codebook, or nullptr to not use a global selector codebook
|
||||
@@ -314,6 +319,12 @@ namespace basisu
|
||||
uint32_t m_max_endpoint_clusters;
|
||||
uint32_t m_max_selector_clusters;
|
||||
int m_quality_level;
|
||||
|
||||
// m_tex_type, m_userdata0, m_userdata1, m_framerate - These fields go directly into the Basis file header.
|
||||
basist::basis_texture_type m_tex_type;
|
||||
uint32_t m_userdata0;
|
||||
uint32_t m_userdata1;
|
||||
uint32_t m_us_per_frame;
|
||||
};
|
||||
|
||||
class basis_compressor
|
||||
@@ -329,6 +340,7 @@ namespace basisu
|
||||
{
|
||||
cECSuccess = 0,
|
||||
cECFailedReadingSourceImages,
|
||||
cECFailedValidating,
|
||||
cECFailedFrontEnd,
|
||||
cECFailedFontendExtract,
|
||||
cECFailedBackend,
|
||||
@@ -349,7 +361,7 @@ namespace basisu
|
||||
private:
|
||||
basis_compressor_params m_params;
|
||||
|
||||
std::vector<image> m_source_images;
|
||||
std::vector<image> m_slice_images;
|
||||
|
||||
std::vector<image_stats> m_stats;
|
||||
|
||||
@@ -390,6 +402,7 @@ namespace basisu
|
||||
bool create_basis_file_and_transcode();
|
||||
bool write_output_files_and_compute_stats();
|
||||
bool generate_mipmaps(const image &img, std::vector<image> &mips, bool has_alpha);
|
||||
bool validate_texture_type_constraints();
|
||||
};
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
@@ -521,17 +521,82 @@ namespace basisu
|
||||
void clear() { clear_obj(*this); }
|
||||
};
|
||||
|
||||
bool create_ktx_texture_file(uint8_vec &ktx_data, const gpu_image_vec& g)
|
||||
// Input is a texture array of mipmapped gpu_image's: gpu_images[array_index][level_index]
|
||||
bool create_ktx_texture_file(uint8_vec &ktx_data, const std::vector<gpu_image_vec>& gpu_images, bool cubemap_flag)
|
||||
{
|
||||
if (!g.size())
|
||||
if (!gpu_images.size())
|
||||
{
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t width = 0, height = 0, total_levels = 0;
|
||||
basisu::texture_format fmt = cInvalidTextureFormat;
|
||||
|
||||
if (cubemap_flag)
|
||||
{
|
||||
if ((gpu_images.size() % 6) != 0)
|
||||
{
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++)
|
||||
{
|
||||
const gpu_image_vec &levels = gpu_images[array_index];
|
||||
|
||||
if (!levels.size())
|
||||
{
|
||||
// Empty mip chain
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array_index)
|
||||
{
|
||||
width = levels[0].get_width();
|
||||
height = levels[0].get_height();
|
||||
total_levels = (uint32_t)levels.size();
|
||||
fmt = levels[0].get_format();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((width != levels[0].get_width()) ||
|
||||
(height != levels[0].get_height()) ||
|
||||
(total_levels != levels.size()))
|
||||
{
|
||||
// All cubemap/texture array faces must be the same dimension
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t level_index = 0; level_index < levels.size(); level_index++)
|
||||
{
|
||||
if (level_index)
|
||||
{
|
||||
if ( (levels[level_index].get_width() != maximum<uint32_t>(1, levels[0].get_width() >> level_index)) ||
|
||||
(levels[level_index].get_height() != maximum<uint32_t>(1, levels[0].get_height() >> level_index)) )
|
||||
{
|
||||
// Malformed mipmap chain
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt != levels[level_index].get_format())
|
||||
{
|
||||
// All input textures must use the same GPU format
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t internal_fmt = KTX_ETC1_RGB8_OES, base_internal_fmt = KTX_RGB;
|
||||
|
||||
switch (g[0].get_format())
|
||||
switch (fmt)
|
||||
{
|
||||
case cBC1:
|
||||
{
|
||||
@@ -602,51 +667,63 @@ namespace basisu
|
||||
header.clear();
|
||||
memcpy(&header.m_identifier, g_ktx_file_id, sizeof(g_ktx_file_id));
|
||||
header.m_endianness = KTX_ENDIAN;
|
||||
header.m_pixelWidth = g[0].get_width();
|
||||
header.m_pixelHeight = g[0].get_height();
|
||||
|
||||
header.m_pixelWidth = width;
|
||||
header.m_pixelHeight = height;
|
||||
|
||||
header.m_glInternalFormat = internal_fmt;
|
||||
header.m_glBaseInternalFormat = base_internal_fmt;
|
||||
header.m_numberOfMipmapLevels = (uint32_t)g.size();
|
||||
header.m_numberOfFaces = 1;
|
||||
|
||||
header.m_numberOfArrayElements = (uint32_t)(cubemap_flag ? (gpu_images.size() / 6) : gpu_images.size());
|
||||
if (header.m_numberOfArrayElements == 1)
|
||||
header.m_numberOfArrayElements = 0;
|
||||
|
||||
header.m_numberOfMipmapLevels = total_levels;
|
||||
header.m_numberOfFaces = cubemap_flag ? 6 : 1;
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)&header, sizeof(header));
|
||||
|
||||
for (uint32_t level = 0; level < g.size(); level++)
|
||||
|
||||
for (uint32_t level_index = 0; level_index < total_levels; level_index++)
|
||||
{
|
||||
const gpu_image& img = g[level];
|
||||
|
||||
if (level)
|
||||
{
|
||||
if ( (img.get_format() != g[0].get_format()) ||
|
||||
(img.get_width() != maximum<uint32_t>(1, g[0].get_width() >> level)) ||
|
||||
(img.get_height() != maximum<uint32_t>(1, g[0].get_height() >> level)) )
|
||||
{
|
||||
// Bad input
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
packed_uint<4> img_size = (uint32_t)img.get_size_in_bytes();
|
||||
|
||||
assert(img_size && ((img_size & 3) == 0));
|
||||
uint32_t img_size = gpu_images[0][level_index].get_size_in_bytes();
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)&img_size, sizeof(img_size));
|
||||
img_size = img_size * header.m_numberOfFaces * maximum<uint32_t>(1, header.m_numberOfArrayElements);
|
||||
|
||||
assert(img_size && ((img_size & 3) == 0));
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)img.get_ptr(), img.get_size_in_bytes());
|
||||
}
|
||||
packed_uint<4> packed_img_size(img_size);
|
||||
append_vector(ktx_data, (uint8_t *)&packed_img_size, sizeof(packed_img_size));
|
||||
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
for (uint32_t array_index = 0; array_index < maximum<uint32_t>(1, header.m_numberOfArrayElements); array_index++)
|
||||
{
|
||||
for (uint32_t face_index = 0; face_index < header.m_numberOfFaces; face_index++)
|
||||
{
|
||||
const gpu_image& img = gpu_images[cubemap_flag ? (array_index * 6 + face_index) : array_index][level_index];
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)img.get_ptr(), img.get_size_in_bytes());
|
||||
|
||||
bytes_written += img.get_size_in_bytes();
|
||||
}
|
||||
|
||||
} // array_index
|
||||
|
||||
assert(bytes_written == img_size);
|
||||
|
||||
} // level_index
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image_vec& g)
|
||||
bool write_compressed_texture_file(const char* pFilename, const std::vector<gpu_image_vec>& g, bool cubemap_flag)
|
||||
{
|
||||
std::string extension(string_tolower(string_get_extension(pFilename)));
|
||||
|
||||
uint8_vec filedata;
|
||||
if (extension == "ktx")
|
||||
{
|
||||
if (!create_ktx_texture_file(filedata, g))
|
||||
if (!create_ktx_texture_file(filedata, g, cubemap_flag))
|
||||
return false;
|
||||
}
|
||||
else if (extension == "pvr")
|
||||
@@ -671,9 +748,9 @@ namespace basisu
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image& g)
|
||||
{
|
||||
gpu_image_vec v;
|
||||
v.push_back(g);
|
||||
return write_compressed_texture_file(pFilename, v);
|
||||
std::vector<gpu_image_vec> v;
|
||||
enlarge_vector(v, 1)->push_back(g);
|
||||
return write_compressed_texture_file(pFilename, v, false);
|
||||
}
|
||||
|
||||
} // basisu
|
||||
|
||||
@@ -110,13 +110,18 @@ namespace basisu
|
||||
|
||||
// KTX file writing
|
||||
|
||||
bool create_ktx_texture_file(uint8_vec &ktx_data, const gpu_image_vec& g);
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image& g);
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image_vec& g);
|
||||
bool create_ktx_texture_file(uint8_vec &ktx_data, const std::vector<gpu_image_vec>& gpu_images, bool cubemap_flag);
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const std::vector<gpu_image_vec>& g, bool cubemap_flag);
|
||||
|
||||
inline bool write_compressed_texture_file(const std::string &filename, const gpu_image &g) { return write_compressed_texture_file(filename.c_str(), g); }
|
||||
inline bool write_compressed_texture_file(const std::string &filename, const gpu_image_vec &g) { return write_compressed_texture_file(filename.c_str(), g); }
|
||||
inline bool write_compressed_texture_file(const char *pFilename, const gpu_image_vec &g)
|
||||
{
|
||||
std::vector<gpu_image_vec> a;
|
||||
a.push_back(g);
|
||||
return write_compressed_texture_file(pFilename, a, false);
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g);
|
||||
|
||||
// GPU texture block unpacking
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@ static void print_usage()
|
||||
" -debug_images: Enable codec debug images (much slower)\n"
|
||||
" -compute_stats: Compute and display image quality metrics (slightly slower)\n"
|
||||
" -slower: Enable optional stages in the compressor for slower but higher quality compression\n"
|
||||
" -tex_type <2d, 2darray, 3d, video, cubemap>: Set Basis file header's texture type field. Cubemap arrays require multiples of 6 images, in X+, X-, Y+, Y-, Z+, Z- order, each image must be the same resolutions.\n"
|
||||
" (2d=arbitrary 2D images, 2darray=2D array, 3D=volume texture slices, video=video frames, cubemap=array of faces. For 2darray/3d/cubemaps/video, each source image's dimensions and # of mipmap levels must be the same.)"
|
||||
" -framerate X: Set framerate in header to X/frames sec\n"
|
||||
"\n"
|
||||
"More options:\n"
|
||||
" -max_endpoint_clusters X: Manually set the max number of color endpoint clusters from 1-8192, use instead of -q\n"
|
||||
@@ -98,6 +101,10 @@ static void print_usage()
|
||||
" -no_endpoint_refinement: Disable endpoint codebook refinement stage (slightly faster, but lower quality)\n"
|
||||
" -hybrid_sel_cb_quality_thresh X: Set hybrid selector codebook quality threshold, default is 2.0, try 1.5-3, higher is lower quality/smaller codebooks\n"
|
||||
"\n"
|
||||
"Set various fields in the Basis file header:\n"
|
||||
" -userdata0 X: Set 32-bit userdata0 field in Basis file header to X (X is a signed 32-bit int)\n"
|
||||
" -userdata1 X: Set 32-bit userdata1 field in Basis file header to X (X is a signed 32-bit int)\n"
|
||||
"\n"
|
||||
"Various command line examples:\n"
|
||||
"basisu -srgb -file x.png -mipmap -y_flip : Compress a mipmapped x.basis file from an sRGB image named x.png, Y flip each source image\n"
|
||||
"basisu -validate -file x.basis : Validate x.basis (check header, check file CRC's, attempt to transcode all slices)\n"
|
||||
@@ -295,6 +302,50 @@ public:
|
||||
m_comp_params.m_hybrid_sel_cb_quality_thresh = (float)atof(arg_v[arg_index + 1]);
|
||||
arg_count++;
|
||||
}
|
||||
else if (strcasecmp(pArg, "-userdata0") == 0)
|
||||
{
|
||||
REMAINING_ARGS_CHECK(1);
|
||||
m_comp_params.m_userdata0 = atoi(arg_v[arg_index + 1]);
|
||||
arg_count++;
|
||||
}
|
||||
else if (strcasecmp(pArg, "-userdata1") == 0)
|
||||
{
|
||||
REMAINING_ARGS_CHECK(1);
|
||||
m_comp_params.m_userdata1 = atoi(arg_v[arg_index + 1]);
|
||||
arg_count++;
|
||||
}
|
||||
else if (strcasecmp(pArg, "-framerate") == 0)
|
||||
{
|
||||
REMAINING_ARGS_CHECK(1);
|
||||
double fps = atof(arg_v[arg_index + 1]);
|
||||
double us_per_frame = 0;
|
||||
if (fps > 0)
|
||||
us_per_frame = 1000000.0f / fps;
|
||||
|
||||
m_comp_params.m_us_per_frame = clamp<int>(static_cast<int>(us_per_frame + .5f), 0, basist::cBASISMaxUSPerFrame);
|
||||
arg_count++;
|
||||
}
|
||||
else if (strcasecmp(pArg, "-tex_type") == 0)
|
||||
{
|
||||
REMAINING_ARGS_CHECK(1);
|
||||
const char *pType = arg_v[arg_index + 1];
|
||||
if (strcasecmp(pType, "2d") == 0)
|
||||
m_comp_params.m_tex_type = basist::cBASISTexType2D;
|
||||
else if (strcasecmp(pType, "2darray") == 0)
|
||||
m_comp_params.m_tex_type = basist::cBASISTexType2DArray;
|
||||
else if (strcasecmp(pType, "3d") == 0)
|
||||
m_comp_params.m_tex_type = basist::cBASISTexTypeVolume;
|
||||
else if (strcasecmp(pType, "cubemap") == 0)
|
||||
m_comp_params.m_tex_type = basist::cBASISTexTypeCubemapArray;
|
||||
else if (strcasecmp(pType, "video") == 0)
|
||||
m_comp_params.m_tex_type = basist::cBASISTexTypeVideoFrames;
|
||||
else
|
||||
{
|
||||
error_printf("Invalid texture type: %s\n", pType);
|
||||
return false;
|
||||
}
|
||||
arg_count++;
|
||||
}
|
||||
else if (pArg[0] == '-')
|
||||
{
|
||||
error_printf("Unrecognized command line option: %s\n", pArg);
|
||||
@@ -433,6 +484,9 @@ static bool compress_mode(command_line_params &opts)
|
||||
case basis_compressor::cECFailedReadingSourceImages:
|
||||
error_printf("Compressor failed reading a source image!\n");
|
||||
break;
|
||||
case basis_compressor::cECFailedValidating:
|
||||
error_printf("Compressor failed 2darray/cubemap/video validation checks!\n");
|
||||
break;
|
||||
case basis_compressor::cECFailedFrontEnd:
|
||||
error_printf("Compressor frontend stage failed!\n");
|
||||
break;
|
||||
@@ -507,11 +561,11 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
|
||||
// Validate the file - note this isn't necessary for transcoding
|
||||
if (!dec.validate_file_checksums(&basis_data[0], (uint32_t)basis_data.size(), true))
|
||||
{
|
||||
error_printf("File failed CRC checks!\n");
|
||||
error_printf("File version is unsupported, or file fail CRC checks!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("File CRC checks succeeded\n");
|
||||
printf("File version and CRC checks succeeded\n");
|
||||
|
||||
basist::basisu_file_info fileinfo;
|
||||
if (!dec.get_file_info(&basis_data[0], (uint32_t)basis_data.size(), fileinfo))
|
||||
@@ -532,14 +586,17 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
|
||||
printf(" Endpoint codebook size: %u\n", fileinfo.m_endpoint_codebook_size);
|
||||
printf(" Tables size: %u\n", fileinfo.m_tables_size);
|
||||
printf(" Slices size: %u\n", fileinfo.m_slices_size);
|
||||
printf(" Texture type: %s\n", basist::basis_get_texture_type_name(fileinfo.m_tex_type));
|
||||
printf(" us per frame: %u (%f fps)\n", fileinfo.m_us_per_frame, fileinfo.m_us_per_frame ? (1.0f / ((float)fileinfo.m_us_per_frame / 1000000.0f)) : 0.0f);
|
||||
printf(" Total slices: %u\n", (uint32_t)fileinfo.m_slice_info.size());
|
||||
printf(" Total images: %i\n", fileinfo.m_total_images);
|
||||
printf(" Image mipmap levels: ");
|
||||
printf(" Y Flipped: %u, Has alpha slices: %u\n", fileinfo.m_y_flipped, fileinfo.m_has_alpha_slices);
|
||||
printf(" userdata0: 0x%X userdata1: 0x%X\n", fileinfo.m_userdata0, fileinfo.m_userdata1);
|
||||
printf(" Per-image mipmap levels: ");
|
||||
for (uint32_t i = 0; i < fileinfo.m_total_images; i++)
|
||||
printf("%u ", fileinfo.m_image_mipmap_levels[i]);
|
||||
printf("\n");
|
||||
printf(" Y Flipped: %u, Has alpha slices: %u\n", fileinfo.m_y_flipped, fileinfo.m_has_alpha_slices);
|
||||
|
||||
|
||||
if (!dec.start_transcoding(&basis_data[0], (uint32_t)basis_data.size()))
|
||||
{
|
||||
error_printf("start_transcoding() failed!\n");
|
||||
@@ -615,6 +672,25 @@ 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 (fileinfo.m_tex_type == basist::cBASISTexTypeCubemapArray)
|
||||
{
|
||||
// No KTX tool that we know of supports cubemap arrays, so write individual cubemap files.
|
||||
for (uint32_t image_index = 0; image_index < fileinfo.m_total_images; image_index += 6)
|
||||
{
|
||||
std::vector<gpu_image_vec> cubemap;
|
||||
for (uint32_t i = 0; i < 6; i++)
|
||||
cubemap.push_back(gpu_images[format_iter][image_index + i]);
|
||||
|
||||
std::string ktx_filename(base_filename + string_format("_transcoded_cubemap_%s_%u.ktx", basist::basis_get_format_name(transcoder_tex_fmt), image_index / 6));
|
||||
if (!write_compressed_texture_file(ktx_filename.c_str(), cubemap, true))
|
||||
{
|
||||
error_printf("Failed writing KTX file \"%s\"!\n", ktx_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
printf("Wrote KTX file \"%s\"\n", ktx_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t image_index = 0; image_index < fileinfo.m_total_images; image_index++)
|
||||
{
|
||||
gpu_image_vec &gi = gpu_images[format_iter][image_index];
|
||||
@@ -630,13 +706,16 @@ static bool unpack_and_validate_mode(command_line_params &opts, bool validate_fl
|
||||
if (level < gi.size())
|
||||
continue;
|
||||
|
||||
std::string ktx_filename(base_filename + string_format("_transcoded_%s_%u.ktx", basist::basis_get_format_name(transcoder_tex_fmt), image_index));
|
||||
if (!write_compressed_texture_file(ktx_filename, gi))
|
||||
if (fileinfo.m_tex_type != basist::cBASISTexTypeCubemapArray)
|
||||
{
|
||||
error_printf("Failed writing KTX file \"%s\"!\n", ktx_filename.c_str());
|
||||
return false;
|
||||
std::string ktx_filename(base_filename + string_format("_transcoded_%s_%u.ktx", basist::basis_get_format_name(transcoder_tex_fmt), image_index));
|
||||
if (!write_compressed_texture_file(ktx_filename.c_str(), gi))
|
||||
{
|
||||
error_printf("Failed writing KTX file \"%s\"!\n", ktx_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
printf("Wrote KTX file \"%s\"\n", ktx_filename.c_str());
|
||||
}
|
||||
printf("Wrote KTX file \"%s\"\n", ktx_filename.c_str());
|
||||
|
||||
for (uint32_t level_index = 0; level_index < gi.size(); level_index++)
|
||||
{
|
||||
|
||||
@@ -42,12 +42,27 @@ namespace basist
|
||||
basisu::packed_uint<2> m_slice_data_crc16;
|
||||
};
|
||||
|
||||
enum
|
||||
enum basis_header_flags
|
||||
{
|
||||
cBASISHeaderFlagETC1S = 1,
|
||||
cBASISHeaderFlagYFlipped = 2,
|
||||
cBASISHeaderFlagHasAlphaSlices = 4,
|
||||
cBASISHeaderFlagHasExtendedData = 8
|
||||
cBASISHeaderFlagHasAlphaSlices = 4
|
||||
};
|
||||
|
||||
// The image type field attempts to describe how to interpret the image data in a Basis file.
|
||||
// The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user.
|
||||
enum basis_texture_type
|
||||
{
|
||||
cBASISTexType2D = 0, // An arbitrary array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image may have a different resolution and # of mipmap levels
|
||||
cBASISTexType2DArray = 1, // An array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image has the same resolution and mipmap levels
|
||||
cBASISTexTypeCubemapArray = 2, // an array of cubemap levels, total # of images must be divisable by 6, in X+, X-, Y+, Y-, Z+, Z- order, with optional mipmaps
|
||||
cBASISTexTypeVideoFrames = 3, // An array of 2D video frames, with optional mipmaps, # frames = # images, each image has the same resolution and # of mipmap levels
|
||||
cBASISTexTypeVolume = 4 // A 3D texture with optional mipmaps, Z dimension = # images, each image has the same resolution and # of mipmap levels
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
cBASISMaxUSPerFrame = 0xFFFFFF
|
||||
};
|
||||
|
||||
struct basis_file_header
|
||||
@@ -71,7 +86,9 @@ namespace basist
|
||||
basisu::packed_uint<3> m_total_images;
|
||||
|
||||
basisu::packed_uint<1> m_format; // enum basist::block_format
|
||||
basisu::packed_uint<2> m_flags;
|
||||
basisu::packed_uint<2> m_flags; // enum basist::header_flags
|
||||
basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type
|
||||
basisu::packed_uint<3> m_us_per_frame; // framerate of video, in microseconds per frame
|
||||
|
||||
basisu::packed_uint<4> m_reserved;
|
||||
basisu::packed_uint<4> m_userdata0;
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "basisu_transcoder.h"
|
||||
#include "basisu_file_headers.h"
|
||||
#include <limits.h>
|
||||
#include <vector>
|
||||
|
||||
// The supported .basis file header version. Keep in sync with BASIS_FILE_VERSION.
|
||||
#define BASISD_SUPPORTED_BASIS_VERSION (0x11)
|
||||
#define BASISD_SUPPORTED_BASIS_VERSION (0x12)
|
||||
|
||||
#define BASISD_SUPPORT_DXT1 1
|
||||
#define BASISD_SUPPORT_DXT5A 1
|
||||
@@ -3895,6 +3894,34 @@ namespace basist
|
||||
return true;
|
||||
}
|
||||
|
||||
basis_texture_type basisu_transcoder::get_texture_type(const void *pData, uint32_t data_size) const
|
||||
{
|
||||
if (!validate_header_quick(pData, data_size))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_texture_type: header validation failed\n");
|
||||
return cBASISTexType2DArray;
|
||||
}
|
||||
|
||||
const basis_file_header *pHeader = static_cast<const basis_file_header *>(pData);
|
||||
|
||||
return static_cast<basis_texture_type>(static_cast<uint8_t>(pHeader->m_tex_type));
|
||||
}
|
||||
|
||||
bool basisu_transcoder::get_userdata(const void *pData, uint32_t data_size, uint32_t &userdata0, uint32_t &userdata1) const
|
||||
{
|
||||
if (!validate_header_quick(pData, data_size))
|
||||
{
|
||||
BASISU_DEVEL_ERROR("basisu_transcoder::get_userdata: header validation failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const basis_file_header *pHeader = static_cast<const basis_file_header *>(pData);
|
||||
|
||||
userdata0 = pHeader->m_userdata0;
|
||||
userdata1 = pHeader->m_userdata1;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t basisu_transcoder::get_total_images(const void *pData, uint32_t data_size) const
|
||||
{
|
||||
if (!validate_header_quick(pData, data_size))
|
||||
@@ -4100,6 +4127,11 @@ namespace basist
|
||||
file_info.m_slice_info.resize(total_slices);
|
||||
|
||||
file_info.m_slices_size = 0;
|
||||
|
||||
file_info.m_tex_type = static_cast<basis_texture_type>(static_cast<uint8_t>(pHeader->m_tex_type));
|
||||
file_info.m_us_per_frame = pHeader->m_us_per_frame;
|
||||
file_info.m_userdata0 = pHeader->m_userdata0;
|
||||
file_info.m_userdata1 = pHeader->m_userdata1;
|
||||
|
||||
file_info.m_image_mipmap_levels.resize(0);
|
||||
file_info.m_image_mipmap_levels.resize(pHeader->m_total_images);
|
||||
@@ -4673,6 +4705,23 @@ namespace basist
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *basis_get_texture_type_name(basis_texture_type tex_type)
|
||||
{
|
||||
switch (tex_type)
|
||||
{
|
||||
case cBASISTexType2D: return "2D";
|
||||
case cBASISTexType2DArray: return "2D array";
|
||||
case cBASISTexTypeCubemapArray: return "cubemap array";
|
||||
case cBASISTexTypeVideoFrames: return "video";
|
||||
case cBASISTexTypeVolume: return "3D";
|
||||
default:
|
||||
assert(0);
|
||||
BASISU_DEVEL_ERROR("basis_get_texture_type_name: Invalid tex_type\n");
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "basisu_transcoder_internal.h"
|
||||
#include "basisu_global_selector_palette.h"
|
||||
#include "basisu_file_headers.h"
|
||||
|
||||
namespace basist
|
||||
{
|
||||
@@ -55,6 +56,7 @@ namespace basist
|
||||
const char *basis_get_format_name(transcoder_texture_format fmt);
|
||||
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);
|
||||
|
||||
class basisu_transcoder;
|
||||
|
||||
@@ -173,11 +175,17 @@ namespace basist
|
||||
uint32_t m_tables_size;
|
||||
uint32_t m_slices_size;
|
||||
|
||||
basis_texture_type m_tex_type;
|
||||
uint32_t m_us_per_frame;
|
||||
|
||||
// Low-level slice information (1 slice per image for color-only basis files, 2 for alpha basis files)
|
||||
basisu_slice_info_vec m_slice_info;
|
||||
|
||||
uint32_t m_total_images; // total # of images
|
||||
std::vector<uint32_t> m_image_mipmap_levels; // the # of mipmap levels for each image
|
||||
|
||||
uint32_t m_userdata0;
|
||||
uint32_t m_userdata1;
|
||||
|
||||
bool m_etc1s; // always true for basis universal
|
||||
bool m_y_flipped; // true if the image was Y flipped
|
||||
@@ -197,6 +205,9 @@ namespace basist
|
||||
|
||||
// Quick header validation - no crc16 checks.
|
||||
bool validate_header(const void *pData, uint32_t data_size) const;
|
||||
|
||||
basis_texture_type get_texture_type(const void *pData, uint32_t data_size) const;
|
||||
bool get_userdata(const void *pData, uint32_t data_size, uint32_t &userdata0, uint32_t &userdata1) const;
|
||||
|
||||
// Returns the total number of images in the basis file (always 1 or more).
|
||||
// Note that the number of mipmap levels for each image may differ, and that images may have different resolutions.
|
||||
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -296,7 +296,7 @@ function viewAlpha() { drawMode = 2; redraw(); }
|
||||
<br>
|
||||
<br>
|
||||
.basis file:
|
||||
<input id="file" type="text" size=30 value="xmen.basis"></input>
|
||||
<input id="file" type="text" size=30 value="kodim20.basis"></input>
|
||||
<input type="button" value="Run!" onclick="run()"></input>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
Binary file not shown.
BIN
webgl/xmen.basis
BIN
webgl/xmen.basis
Binary file not shown.
Reference in New Issue
Block a user