diff options
author | K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> | 2023-02-25 11:59:49 -0800 |
---|---|---|
committer | K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> | 2023-02-25 13:48:51 -0800 |
commit | add503e71d35aefec3b31c82465bab9c0023668a (patch) | |
tree | 6bce2e5088c2d1ef726d6f42018c4f8db3092abd /modules | |
parent | 3863199ab940272f6844ff30910ec7a520e47f41 (diff) |
Fix basisu mipmaps
Previously basisu was storing mip maps as an array of basisu in the internal format for Texture. The new work makes sense and it generates smaller files with one image.
This pull request fixes the basisu decompression and keep the approach of 1 image. If we need to change the format in 4.x, we can still support the old format with some limitations too. Basisu from gltfpack can only output with mipmaps.
The single image will not work for StreamedTexture. We should support both approaches for CompressedTexture we use one, and for StreamedTexture we use another.
Additional error checking for hdr images and for nullptr.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/basis_universal/register_types.cpp | 82 |
1 files changed, 41 insertions, 41 deletions
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index ff7c01f9fc..c5db9b9933 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -58,27 +58,32 @@ static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image:: if (image->get_format() != Image::FORMAT_RGBA8) { image->convert(Image::FORMAT_RGBA8); } - Ref<Image> image_single = image->duplicate(); - { - if (image_single->has_mipmaps()) { - image_single->clear_mipmaps(); - } - basisu::image buimg(image_single->get_width(), image_single->get_height()); - Vector<uint8_t> vec = image_single->get_data(); + if (!image->has_mipmaps()) { + basisu::image buimg(image->get_width(), image->get_height()); + Vector<uint8_t> vec = image->get_data(); const uint8_t *r = vec.ptr(); memcpy(buimg.get_ptr(), r, vec.size()); params.m_source_images.push_back(buimg); + } else { + { + Ref<Image> base_image = image->get_image_from_mipmap(0); + Vector<uint8_t> image_vec = base_image->get_data(); + basisu::image buimg_image(base_image->get_width(), base_image->get_height()); + const uint8_t *r = image_vec.ptr(); + memcpy(buimg_image.get_ptr(), r, image_vec.size()); + params.m_source_images.push_back(buimg_image); + } + basisu::vector<basisu::image> images; + for (int32_t mip_map_i = 1; mip_map_i < image->get_mipmap_count(); mip_map_i++) { + Ref<Image> mip_map = image->get_image_from_mipmap(mip_map_i); + Vector<uint8_t> mip_map_vec = mip_map->get_data(); + basisu::image buimg_mipmap(mip_map->get_width(), mip_map->get_height()); + const uint8_t *r = mip_map_vec.ptr(); + memcpy(buimg_mipmap.get_ptr(), r, mip_map_vec.size()); + images.push_back(buimg_mipmap); + } + params.m_source_mipmap_images.push_back(images); } - basisu::vector<basisu::image> source_images; - for (int32_t mipmap_i = 1; mipmap_i < image->get_mipmap_count(); mipmap_i++) { - Ref<Image> mip = image->get_image_from_mipmap(mipmap_i); - basisu::image buimg(mip->get_width(), mip->get_height()); - Vector<uint8_t> vec = mip->get_data(); - const uint8_t *r = vec.ptr(); - memcpy(buimg.get_ptr(), r, vec.size()); - source_images.push_back(buimg); - } - params.m_uastc = true; params.m_quality_level = basisu::BASISU_QUALITY_MIN; @@ -154,6 +159,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size const uint8_t *ptr = p_data; int size = p_size; + ERR_FAIL_COND_V_MSG(p_data == nullptr, image, "Cannot unpack invalid basis universal data."); basist::transcoder_texture_format format = basist::transcoder_texture_format::cTFTotalTextureFormats; Image::Format imgfmt = Image::FORMAT_MAX; @@ -228,35 +234,29 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image); + tr.start_transcoding(ptr, size); + basist::basisu_image_info info; tr.get_image_info(ptr, size, info, 0); - - int block_size = basist::basis_get_bytes_per_block_or_pixel(format); Vector<uint8_t> gpudata; - gpudata.resize(info.m_total_blocks * block_size); - - { - uint8_t *w = gpudata.ptrw(); - uint8_t *dst = w; - for (int i = 0; i < gpudata.size(); i++) { - dst[i] = 0x00; - } + gpudata.resize(Image::get_image_data_size(info.m_width, info.m_height, imgfmt, info.m_total_levels > 1)); - int ofs = 0; - tr.start_transcoding(ptr, size); - for (uint32_t i = 0; i < info.m_total_levels; i++) { - basist::basisu_image_level_info level; - tr.get_image_level_info(ptr, size, level, 0, i); - - bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format); - if (!ret) { - printf("failed! on level %u\n", i); - break; - }; - - ofs += level.m_total_blocks * block_size; + uint8_t *w = gpudata.ptrw(); + uint8_t *dst = w; + for (int i = 0; i < gpudata.size(); i++) { + dst[i] = 0x00; + } + uint32_t mip_count = Image::get_image_required_mipmaps(info.m_orig_width, info.m_orig_height, imgfmt); + for (uint32_t level_i = 0; level_i < mip_count; level_i++) { + basist::basisu_image_level_info level; + tr.get_image_level_info(ptr, size, level, 0, level_i); + int ofs = Image::get_image_mipmap_offset(info.m_width, info.m_height, imgfmt, level_i); + bool ret = tr.transcode_image_level(ptr, size, 0, level_i, dst + ofs, level.m_total_blocks, format); + if (!ret) { + print_line(vformat("Basis universal cannot unpack level %d.", level_i)); + break; }; - }; + } image = Image::create_from_data(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); |