@@ -96,17 +96,74 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
96
96
} break ;
97
97
}
98
98
99
+ // Copy the source image data with mipmaps into BasisU.
99
100
{
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
+
101
110
Vector<uint8_t > image_data = image->get_data ();
102
111
basisu::vector<basisu::image> basisu_mipmaps;
103
112
113
+ // Buffer for storing padded mipmap data.
114
+ Vector<uint32_t > mip_data_padded;
115
+
104
116
for (int32_t i = 0 ; i <= image->get_mipmap_count (); i++) {
105
117
int ofs, size, width, height;
106
118
image->get_mipmap_offset_size_and_dimensions (i, ofs, size, width, height);
107
119
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.
108
165
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);
110
167
111
168
if (i == 0 ) {
112
169
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
132
189
133
190
// Copy the encoded data to the buffer.
134
191
{
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;
137
194
138
- memcpy (w + 4 , basisu_out.get_ptr (), basisu_out.size ());
195
+ memcpy (wb + 4 , basisu_out.get_ptr (), basisu_out.size ());
139
196
}
140
197
141
198
return basisu_data;
@@ -238,8 +295,7 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
238
295
uint8_t *dst = out_data.ptrw ();
239
296
memset (dst, 0 , out_data.size ());
240
297
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++) {
243
299
basist::basisu_image_level_info basisu_level;
244
300
transcoder.get_image_level_info (src_ptr, src_size, basisu_level, 0 , i);
245
301
0 commit comments