diff --git a/basisu_tool.cpp b/basisu_tool.cpp index 67941e6f..26de1c43 100644 --- a/basisu_tool.cpp +++ b/basisu_tool.cpp @@ -1632,8 +1632,7 @@ static bool compress_mode(command_line_params &opts) if (params.m_tex_type == basist::basis_texture_type::cBASISTexTypeVideoFrames) { // Create KTXanimData key value entry - // TODO: Move this to basisu_comp.h - basist::ktx2_transcoder::key_value kv; + basisu::key_value kv; const char* pAD = "KTXanimData"; kv.m_key.resize(strlen(pAD) + 1); diff --git a/encoder/basisu_comp.cpp b/encoder/basisu_comp.cpp index dee91aaa..eaf290bf 100644 --- a/encoder/basisu_comp.cpp +++ b/encoder/basisu_comp.cpp @@ -4585,18 +4585,18 @@ namespace basisu } // Key values - basist::ktx2_transcoder::key_value_vec key_values(m_params.m_ktx2_key_values); + basisu::key_value_vec key_values(m_params.m_ktx2_key_values); - basist::ktx2_add_key_value(key_values, "KTXwriter", fmt_string("Basis Universal {}", BASISU_LIB_VERSION_STRING)); + basisu::add_key_value(key_values, "KTXwriter", fmt_string("Basis Universal {}", BASISU_LIB_VERSION_STRING)); if (m_params.m_hdr) { if (m_upconverted_any_ldr_images) { - basist::ktx2_add_key_value(key_values, "LDRUpconversionMultiplier", fmt_string("{}", m_ldr_to_hdr_upconversion_nit_multiplier)); + basisu::add_key_value(key_values, "LDRUpconversionMultiplier", fmt_string("{}", m_ldr_to_hdr_upconversion_nit_multiplier)); if (m_params.m_ldr_hdr_upconversion_srgb_to_linear) - basist::ktx2_add_key_value(key_values, "LDRUpconversionSRGBToLinear", "1"); + basisu::add_key_value(key_values, "LDRUpconversionSRGBToLinear", "1"); } // Always write the scale to simplify testing. @@ -4919,7 +4919,8 @@ namespace basisu uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, image_stats* pStats, - int quality_level, int effort_level) + int quality_level, int effort_level, + const basisu::key_value_vec* pKeyValues) { assert((pSource_images != nullptr) || (pSource_images_hdr != nullptr)); assert(!((pSource_images != nullptr) && (pSource_images_hdr != nullptr))); @@ -5135,6 +5136,8 @@ namespace basisu // Set KTX2 specific parameters. if ((flags_and_quality & cFlagKTX2UASTCSuperCompression) && (comp_params.m_uastc)) comp_params.m_ktx2_uastc_supercompression = basist::KTX2_SS_ZSTANDARD; + if (pKeyValues) + comp_params.m_ktx2_key_values = *pKeyValues; } comp_params.m_compute_stats = (pStats != nullptr); @@ -5217,9 +5220,10 @@ namespace basisu const basisu::vector& source_images, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { - return basis_compress_internal(mode, &source_images, nullptr, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats, -1, -1); + return basis_compress_internal(mode, &source_images, nullptr, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats, -1, -1, pKeyValues); } void* basis_compress2( @@ -5227,9 +5231,10 @@ namespace basisu const basisu::vector& source_images, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { - return basis_compress_internal(mode, &source_images, nullptr, flags_and_quality, 0.0f, pSize, pStats, quality_level, effort_level); + return basis_compress_internal(mode, &source_images, nullptr, flags_and_quality, 0.0f, pSize, pStats, quality_level, effort_level, pKeyValues); } void* basis_compress( @@ -5237,9 +5242,10 @@ namespace basisu const basisu::vector& source_images_hdr, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { - return basis_compress_internal(mode, nullptr, &source_images_hdr, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats, -1, -1); + return basis_compress_internal(mode, nullptr, &source_images_hdr, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats, -1, -1, pKeyValues); } void* basis_compress2( @@ -5247,9 +5253,10 @@ namespace basisu const basisu::vector& source_images_hdr, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { - return basis_compress_internal(mode, nullptr, &source_images_hdr, flags_and_quality, 0.0f, pSize, pStats, quality_level, effort_level); + return basis_compress_internal(mode, nullptr, &source_images_hdr, flags_and_quality, 0.0f, pSize, pStats, quality_level, effort_level, pKeyValues); } void* basis_compress( @@ -5257,7 +5264,8 @@ namespace basisu const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { if (!pitch_in_pixels) pitch_in_pixels = width; @@ -5283,7 +5291,7 @@ namespace basisu for (uint32_t y = 0; y < height; y++) memcpy(source_image[0].get_ptr() + y * width, (const color_rgba*)pImageRGBA + y * pitch_in_pixels, width * sizeof(color_rgba)); - return basis_compress(mode, source_image, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats); + return basis_compress(mode, source_image, flags_and_quality, uastc_rdo_or_dct_quality, pSize, pStats, pKeyValues); } void* basis_compress2( @@ -5291,7 +5299,8 @@ namespace basisu const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats) + image_stats* pStats, + const basisu::key_value_vec* pKeyValues) { if (!pitch_in_pixels) pitch_in_pixels = width; @@ -5317,7 +5326,7 @@ namespace basisu for (uint32_t y = 0; y < height; y++) memcpy(source_image[0].get_ptr() + y * width, (const color_rgba*)pImageRGBA + y * pitch_in_pixels, width * sizeof(color_rgba)); - return basis_compress2(mode, source_image, flags_and_quality, quality_level, effort_level, pSize, pStats); + return basis_compress2(mode, source_image, flags_and_quality, quality_level, effort_level, pSize, pStats, pKeyValues); } void basis_free_data(void* p) diff --git a/encoder/basisu_comp.h b/encoder/basisu_comp.h index fd0de37b..d772b8be 100644 --- a/encoder/basisu_comp.h +++ b/encoder/basisu_comp.h @@ -691,7 +691,7 @@ namespace basisu // Internally, the compressor always creates a .basis file then it converts that losslessly to KTX2. bool_param m_create_ktx2_file; basist::ktx2_supercompression m_ktx2_uastc_supercompression; - basist::ktx2_transcoder::key_value_vec m_ktx2_key_values; + basisu::key_value_vec m_ktx2_key_values; param m_ktx2_zstd_supercompression_level; // Note: The default for this parameter (which used to be "m_ktx2_srgb_transfer_func") used to be false, now setting this to true and renaming to m_ktx2_and_basis_srgb_transfer_function. @@ -990,7 +990,8 @@ namespace basisu uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, image_stats* pStats, - int quality_level = -1, int effort_level = -1); + int quality_level = -1, int effort_level = -1, + const basisu::key_value_vec* pKeyValues = nullptr); // This function accepts an array of source images. // If more than one image is provided, it's assumed the images form a mipmap pyramid and automatic mipmap generation is disabled. @@ -1003,7 +1004,8 @@ namespace basisu const basisu::vector &source_images, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); // HDR-only version. // Important: The returned block MUST be manually freed using basis_free_data(). @@ -1012,7 +1014,8 @@ namespace basisu const basisu::vector& source_images_hdr, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); // This function only accepts a single LDR source image. It's just a wrapper for basis_compress() above. // Important: The returned block MUST be manually freed using basis_free_data(). @@ -1021,7 +1024,8 @@ namespace basisu const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels, uint32_t flags_and_quality, float uastc_rdo_or_dct_quality, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); // basis_compress2() variants accept the new unified quality_level and effort_level parameters instead of the old flags/float uastc_rdo_or_dct_quality parameter. // quality_level must be [0,100], effort_level [0,10]. @@ -1030,21 +1034,24 @@ namespace basisu const basisu::vector& source_images, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); void* basis_compress2( basist::basis_tex_format mode, const basisu::vector& source_images_hdr, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); void* basis_compress2( basist::basis_tex_format mode, const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels, uint32_t flags_and_quality, int quality_level, int effort_level, size_t* pSize, - image_stats* pStats = nullptr); + image_stats* pStats = nullptr, + const basisu::key_value_vec* pKeyValues = nullptr); // Frees the dynamically allocated file data returned by basis_compress(). // This MUST be called on the pointer returned by basis_compress() when you're done with it. diff --git a/transcoder/basisu.h b/transcoder/basisu.h index d4e339e9..b020b850 100644 --- a/transcoder/basisu.h +++ b/transcoder/basisu.h @@ -478,6 +478,54 @@ namespace basisu } }; + // Key value field data. + struct key_value + { + // The key field is UTF8 and always zero terminated. + // In memory we always append a zero terminator to the key. + basisu::uint8_vec m_key; + + // The value may be empty. In the KTX2 file it consists of raw bytes which may or may not be zero terminated. + // In memory we always append a zero terminator to the value. + basisu::uint8_vec m_value; + + bool operator< (const key_value& rhs) const { return strcmp((const char*)m_key.data(), (const char *)rhs.m_key.data()) < 0; } + + + }; + typedef basisu::vector key_value_vec; + + // Replaces if the key already exists + inline void add_key_value(key_value_vec& key_values, const std::string& key, const std::string& val) + { + assert(key.size()); + + key_value* p = nullptr; + + // Try to find an existing key + for (size_t i = 0; i < key_values.size(); i++) + { + if (strcmp((const char*)key_values[i].m_key.data(), key.c_str()) == 0) + { + p = &key_values[i]; + break; + } + } + + if (!p) + p = key_values.enlarge(1); + + p->m_key.resize(0); + p->m_value.resize(0); + + p->m_key.resize(key.size() + 1); + memcpy(p->m_key.data(), key.c_str(), key.size()); + + p->m_value.resize(val.size() + 1); + if (val.size()) + memcpy(p->m_value.data(), val.c_str(), val.size()); + } + enum eZero { cZero }; enum eNoClamp { cNoClamp }; diff --git a/transcoder/basisu_transcoder.h b/transcoder/basisu_transcoder.h index e665b7ad..2dff195c 100644 --- a/transcoder/basisu_transcoder.h +++ b/transcoder/basisu_transcoder.h @@ -1209,24 +1209,9 @@ namespace basist ktx2_df_channel_id get_dfd_channel_id0() const { return m_dfd_chan0; } ktx2_df_channel_id get_dfd_channel_id1() const { return m_dfd_chan1; } - // Key value field data. - struct key_value - { - // The key field is UTF8 and always zero terminated. - // In memory we always append a zero terminator to the key. - basisu::uint8_vec m_key; - - // The value may be empty. In the KTX2 file it consists of raw bytes which may or may not be zero terminated. - // In memory we always append a zero terminator to the value. - basisu::uint8_vec m_value; - - bool operator< (const key_value& rhs) const { return strcmp((const char*)m_key.data(), (const char *)rhs.m_key.data()) < 0; } - }; - typedef basisu::vector key_value_vec; - // Returns the array of key-value entries. This may be empty. Valid after init(). // The order of key values fields in this array exactly matches the order they were stored in the file. The keys are supposed to be sorted by their Unicode code points. - const key_value_vec& get_key_values() const { return m_key_values; } + const basisu::key_value_vec& get_key_values() const { return m_key_values; } const basisu::uint8_vec *find_key(const std::string& key_name) const; @@ -1278,7 +1263,7 @@ namespace basist ktx2_header m_header; basisu::vector m_levels; basisu::uint8_vec m_dfd; - key_value_vec m_key_values; + basisu::key_value_vec m_key_values; ktx2_etc1s_global_data_header m_etc1s_header; basisu::vector m_etc1s_image_descs; @@ -1315,37 +1300,6 @@ namespace basist bool read_key_values(); }; - // Replaces if the key already exists - inline void ktx2_add_key_value(ktx2_transcoder::key_value_vec& key_values, const std::string& key, const std::string& val) - { - assert(key.size()); - - basist::ktx2_transcoder::key_value* p = nullptr; - - // Try to find an existing key - for (size_t i = 0; i < key_values.size(); i++) - { - if (strcmp((const char*)key_values[i].m_key.data(), key.c_str()) == 0) - { - p = &key_values[i]; - break; - } - } - - if (!p) - p = key_values.enlarge(1); - - p->m_key.resize(0); - p->m_value.resize(0); - - p->m_key.resize(key.size() + 1); - memcpy(p->m_key.data(), key.c_str(), key.size()); - - p->m_value.resize(val.size() + 1); - if (val.size()) - memcpy(p->m_value.data(), val.c_str(), val.size()); - } - #endif // BASISD_SUPPORT_KTX2 // Returns true if the transcoder was compiled with KTX2 support.