Merge pull request #89426 from BlueCube3310/basisu-mult-of-4
BasisUniversal: Fix artifacts on images with resolutions not divisible by 4
This commit is contained in:
commit
9122286553
|
@ -96,17 +96,74 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the source image data with mipmaps into BasisU.
|
||||||
{
|
{
|
||||||
// Encode the image with mipmaps.
|
const int orig_width = image->get_width();
|
||||||
|
const int orig_height = image->get_height();
|
||||||
|
|
||||||
|
bool is_res_div_4 = (orig_width % 4 == 0) && (orig_height % 4 == 0);
|
||||||
|
|
||||||
|
// Image's resolution rounded up to the nearest values divisible by 4.
|
||||||
|
int next_width = orig_width <= 2 ? orig_width : (orig_width + 3) & ~3;
|
||||||
|
int next_height = orig_height <= 2 ? orig_height : (orig_height + 3) & ~3;
|
||||||
|
|
||||||
Vector<uint8_t> image_data = image->get_data();
|
Vector<uint8_t> image_data = image->get_data();
|
||||||
basisu::vector<basisu::image> basisu_mipmaps;
|
basisu::vector<basisu::image> basisu_mipmaps;
|
||||||
|
|
||||||
|
// Buffer for storing padded mipmap data.
|
||||||
|
Vector<uint32_t> mip_data_padded;
|
||||||
|
|
||||||
for (int32_t i = 0; i <= image->get_mipmap_count(); i++) {
|
for (int32_t i = 0; i <= image->get_mipmap_count(); i++) {
|
||||||
int ofs, size, width, height;
|
int ofs, size, width, height;
|
||||||
image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height);
|
image->get_mipmap_offset_size_and_dimensions(i, ofs, size, width, height);
|
||||||
|
|
||||||
|
const uint8_t *image_mip_data = image_data.ptr() + ofs;
|
||||||
|
|
||||||
|
// Pad the mipmap's data if its resolution isn't divisible by 4.
|
||||||
|
if (image->has_mipmaps() && !is_res_div_4 && (width > 2 && height > 2) && (width != next_width || height != next_height)) {
|
||||||
|
// Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
|
||||||
|
const uint32_t *mip_src_data = reinterpret_cast<const uint32_t *>(image_mip_data);
|
||||||
|
|
||||||
|
// Reserve space in the padded buffer.
|
||||||
|
mip_data_padded.resize(next_width * next_height);
|
||||||
|
uint32_t *data_padded_ptr = mip_data_padded.ptrw();
|
||||||
|
|
||||||
|
// Pad mipmap to the nearest block by smearing.
|
||||||
|
int x = 0, y = 0;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (x = 0; x < width; x++) {
|
||||||
|
data_padded_ptr[next_width * y + x] = mip_src_data[width * y + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, smear in x.
|
||||||
|
for (; x < next_width; x++) {
|
||||||
|
data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, smear in y.
|
||||||
|
for (; y < next_height; y++) {
|
||||||
|
for (x = 0; x < next_width; x++) {
|
||||||
|
data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - next_width];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the image_mip_data pointer with our temporary Vector.
|
||||||
|
image_mip_data = reinterpret_cast<const uint8_t *>(mip_data_padded.ptr());
|
||||||
|
|
||||||
|
// Override the mipmap's properties.
|
||||||
|
width = next_width;
|
||||||
|
height = next_height;
|
||||||
|
size = mip_data_padded.size() * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next mipmap's resolution.
|
||||||
|
next_width /= 2;
|
||||||
|
next_height /= 2;
|
||||||
|
|
||||||
|
// Copy the source mipmap's data to a BasisU image.
|
||||||
basisu::image basisu_image(width, height);
|
basisu::image basisu_image(width, height);
|
||||||
memcpy(basisu_image.get_ptr(), image_data.ptr() + ofs, size);
|
memcpy(basisu_image.get_ptr(), image_mip_data, size);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
params.m_source_images.push_back(basisu_image);
|
params.m_source_images.push_back(basisu_image);
|
||||||
|
@ -132,10 +189,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||||
|
|
||||||
// Copy the encoded data to the buffer.
|
// Copy the encoded data to the buffer.
|
||||||
{
|
{
|
||||||
uint8_t *w = basisu_data.ptrw();
|
uint8_t *wb = basisu_data.ptrw();
|
||||||
*(uint32_t *)w = decompress_format;
|
*(uint32_t *)wb = decompress_format;
|
||||||
|
|
||||||
memcpy(w + 4, basisu_out.get_ptr(), basisu_out.size());
|
memcpy(wb + 4, basisu_out.get_ptr(), basisu_out.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return basisu_data;
|
return basisu_data;
|
||||||
|
@ -238,8 +295,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
||||||
uint8_t *dst = out_data.ptrw();
|
uint8_t *dst = out_data.ptrw();
|
||||||
memset(dst, 0, out_data.size());
|
memset(dst, 0, out_data.size());
|
||||||
|
|
||||||
uint32_t mip_count = Image::get_image_required_mipmaps(basisu_info.m_orig_width, basisu_info.m_orig_height, image_format);
|
for (uint32_t i = 0; i < basisu_info.m_total_levels; i++) {
|
||||||
for (uint32_t i = 0; i <= mip_count; i++) {
|
|
||||||
basist::basisu_image_level_info basisu_level;
|
basist::basisu_image_level_info basisu_level;
|
||||||
transcoder.get_image_level_info(src_ptr, src_size, basisu_level, 0, i);
|
transcoder.get_image_level_info(src_ptr, src_size, basisu_level, 0, i);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue