@@ -96,17 +96,74 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
9696 } break ;
9797 }
9898
99+ // Copy the source image data with mipmaps into BasisU.
99100 {
100- // Encode the image with mipmaps.
101+ const int orig_width = image->get_width ();
102+ const int orig_height = image->get_height ();
103+
104+ bool is_res_div_4 = (orig_width % 4 == 0 ) && (orig_height % 4 == 0 );
105+
106+ // Image's resolution rounded up to the nearest values divisible by 4.
107+ int next_width = orig_width <= 2 ? orig_width : (orig_width + 3 ) & ~3 ;
108+ int next_height = orig_height <= 2 ? orig_height : (orig_height + 3 ) & ~3 ;
109+
101110 Vector<uint8_t > image_data = image->get_data ();
102111 basisu::vector<basisu::image> basisu_mipmaps;
103112
113+ // Buffer for storing padded mipmap data.
114+ Vector<uint32_t > mip_data_padded;
115+
104116 for (int32_t i = 0 ; i <= image->get_mipmap_count (); i++) {
105117 int ofs, size, width, height;
106118 image->get_mipmap_offset_size_and_dimensions (i, ofs, size, width, height);
107119
120+ const uint8_t *image_mip_data = image_data.ptr () + ofs;
121+
122+ // Pad the mipmap's data if its resolution isn't divisible by 4.
123+ if (image->has_mipmaps () && !is_res_div_4 && (width > 2 && height > 2 ) && (width != next_width || height != next_height)) {
124+ // Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
125+ const uint32_t *mip_src_data = reinterpret_cast <const uint32_t *>(image_mip_data);
126+
127+ // Reserve space in the padded buffer.
128+ mip_data_padded.resize (next_width * next_height);
129+ uint32_t *data_padded_ptr = mip_data_padded.ptrw ();
130+
131+ // Pad mipmap to the nearest block by smearing.
132+ int x = 0 , y = 0 ;
133+ for (y = 0 ; y < height; y++) {
134+ for (x = 0 ; x < width; x++) {
135+ data_padded_ptr[next_width * y + x] = mip_src_data[width * y + x];
136+ }
137+
138+ // First, smear in x.
139+ for (; x < next_width; x++) {
140+ data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - 1 ];
141+ }
142+ }
143+
144+ // Then, smear in y.
145+ for (; y < next_height; y++) {
146+ for (x = 0 ; x < next_width; x++) {
147+ data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - next_width];
148+ }
149+ }
150+
151+ // Override the image_mip_data pointer with our temporary Vector.
152+ image_mip_data = reinterpret_cast <const uint8_t *>(mip_data_padded.ptr ());
153+
154+ // Override the mipmap's properties.
155+ width = next_width;
156+ height = next_height;
157+ size = mip_data_padded.size () * 4 ;
158+ }
159+
160+ // Get the next mipmap's resolution.
161+ next_width /= 2 ;
162+ next_height /= 2 ;
163+
164+ // Copy the source mipmap's data to a BasisU image.
108165 basisu::image basisu_image (width, height);
109- memcpy (basisu_image.get_ptr (), image_data. ptr () + ofs , size);
166+ memcpy (basisu_image.get_ptr (), image_mip_data , size);
110167
111168 if (i == 0 ) {
112169 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
132189
133190 // Copy the encoded data to the buffer.
134191 {
135- uint8_t *w = basisu_data.ptrw ();
136- *(uint32_t *)w = decompress_format;
192+ uint8_t *wb = basisu_data.ptrw ();
193+ *(uint32_t *)wb = decompress_format;
137194
138- memcpy (w + 4 , basisu_out.get_ptr (), basisu_out.size ());
195+ memcpy (wb + 4 , basisu_out.get_ptr (), basisu_out.size ());
139196 }
140197
141198 return basisu_data;
@@ -238,8 +295,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
238295 uint8_t *dst = out_data.ptrw ();
239296 memset (dst, 0 , out_data.size ());
240297
241- uint32_t mip_count = Image::get_image_required_mipmaps (basisu_info.m_orig_width , basisu_info.m_orig_height , image_format);
242- for (uint32_t i = 0 ; i <= mip_count; i++) {
298+ for (uint32_t i = 0 ; i < basisu_info.m_total_levels ; i++) {
243299 basist::basisu_image_level_info basisu_level;
244300 transcoder.get_image_level_info (src_ptr, src_size, basisu_level, 0 , i);
245301
0 commit comments