@@ -5,13 +5,17 @@ use std::io::Read;
5
5
use basis_universal:: {
6
6
DecodeFlags , LowLevelUastcTranscoder , SliceParametersUastc , TranscoderBlockFormat ,
7
7
} ;
8
+ use bevy_utils:: default;
8
9
#[ cfg( any( feature = "flate2" , feature = "ruzstd" ) ) ]
9
10
use ktx2:: SupercompressionScheme ;
10
11
use ktx2:: {
11
12
BasicDataFormatDescriptor , ChannelTypeQualifiers , ColorModel , DataFormatDescriptorHeader ,
12
13
Header , SampleInformation ,
13
14
} ;
14
- use wgpu:: { AstcBlock , AstcChannel , Extent3d , TextureDimension , TextureFormat } ;
15
+ use wgpu:: {
16
+ AstcBlock , AstcChannel , Extent3d , TextureDimension , TextureFormat , TextureViewDescriptor ,
17
+ TextureViewDimension ,
18
+ } ;
15
19
16
20
use super :: { CompressedImageFormats , DataFormat , Image , TextureError , TranscodeFormat } ;
17
21
@@ -28,10 +32,14 @@ pub fn ktx2_buffer_to_image(
28
32
pixel_height : height,
29
33
pixel_depth : depth,
30
34
layer_count,
35
+ face_count,
31
36
level_count,
32
37
supercompression_scheme,
33
38
..
34
39
} = ktx2. header ( ) ;
40
+ let layer_count = layer_count. max ( 1 ) ;
41
+ let face_count = face_count. max ( 1 ) ;
42
+ let depth = depth. max ( 1 ) ;
35
43
36
44
// Handle supercompression
37
45
let mut levels = Vec :: new ( ) ;
@@ -80,25 +88,25 @@ pub fn ktx2_buffer_to_image(
80
88
let texture_format = ktx2_get_texture_format ( & ktx2, is_srgb) . or_else ( |error| match error {
81
89
// Transcode if needed and supported
82
90
TextureError :: FormatRequiresTranscodingError ( transcode_format) => {
83
- let mut transcoded = Vec :: new ( ) ;
91
+ let mut transcoded = vec ! [ Vec :: default ( ) ; levels . len ( ) ] ;
84
92
let texture_format = match transcode_format {
85
93
TranscodeFormat :: Rgb8 => {
86
- let ( mut original_width, mut original_height) = ( width, height) ;
87
-
88
- for level_data in & levels {
89
- let n_pixels = ( original_width * original_height) as usize ;
94
+ let mut rgba = vec ! [ 255u8 ; width as usize * height as usize * 4 ] ;
95
+ for ( level, level_data) in levels. iter ( ) . enumerate ( ) {
96
+ let n_pixels = ( width as usize >> level) . max ( 1 ) * ( height as usize >> level) . max ( 1 ) ;
90
97
91
- let mut rgba = vec ! [ 255u8 ; n_pixels * 4 ] ;
92
- for i in 0 ..n_pixels {
93
- rgba[ i * 4 ] = level_data[ i * 3 ] ;
94
- rgba[ i * 4 + 1 ] = level_data[ i * 3 + 1 ] ;
95
- rgba[ i * 4 + 2 ] = level_data[ i * 3 + 2 ] ;
98
+ let mut offset = 0 ;
99
+ for _layer in 0 ..layer_count {
100
+ for _face in 0 ..face_count {
101
+ for i in 0 ..n_pixels {
102
+ rgba[ i * 4 ] = level_data[ offset] ;
103
+ rgba[ i * 4 + 1 ] = level_data[ offset + 1 ] ;
104
+ rgba[ i * 4 + 2 ] = level_data[ offset + 2 ] ;
105
+ offset += 3 ;
106
+ }
107
+ transcoded[ level] . extend_from_slice ( & rgba[ 0 ..n_pixels] ) ;
108
+ }
96
109
}
97
- transcoded. push ( rgba) ;
98
-
99
- // Next mip dimensions are half the current, minimum 1x1
100
- original_width = ( original_width / 2 ) . max ( 1 ) ;
101
- original_height = ( original_height / 2 ) . max ( 1 ) ;
102
110
}
103
111
104
112
if is_srgb {
@@ -111,41 +119,54 @@ pub fn ktx2_buffer_to_image(
111
119
TranscodeFormat :: Uastc ( data_format) => {
112
120
let ( transcode_block_format, texture_format) =
113
121
get_transcoded_formats ( supported_compressed_formats, data_format, is_srgb) ;
114
- let ( mut original_width, mut original_height) = ( width, height) ;
115
- let ( block_width_pixels, block_height_pixels) = ( 4 , 4 ) ;
122
+ let texture_format_info = texture_format. describe ( ) ;
123
+ let ( block_width_pixels, block_height_pixels) = (
124
+ texture_format_info. block_dimensions . 0 as u32 ,
125
+ texture_format_info. block_dimensions . 1 as u32 ,
126
+ ) ;
127
+ let block_bytes = texture_format_info. block_size as u32 ;
116
128
117
129
let transcoder = LowLevelUastcTranscoder :: new ( ) ;
118
130
for ( level, level_data) in levels. iter ( ) . enumerate ( ) {
119
- let slice_parameters = SliceParametersUastc {
120
- num_blocks_x : ( ( original_width + block_width_pixels - 1 )
121
- / block_width_pixels)
122
- . max ( 1 ) ,
123
- num_blocks_y : ( ( original_height + block_height_pixels - 1 )
124
- / block_height_pixels)
125
- . max ( 1 ) ,
126
- has_alpha : false ,
127
- original_width,
128
- original_height,
129
- } ;
130
-
131
- transcoder
132
- . transcode_slice (
133
- level_data,
134
- slice_parameters,
135
- DecodeFlags :: HIGH_QUALITY ,
136
- transcode_block_format,
137
- )
138
- . map ( |transcoded_level| transcoded. push ( transcoded_level) )
139
- . map_err ( |error| {
140
- TextureError :: SuperDecompressionError ( format ! (
141
- "Failed to transcode mip level {} from UASTC to {:?}: {:?}" ,
142
- level, transcode_block_format, error
143
- ) )
144
- } ) ?;
131
+ let ( level_width, level_height) = (
132
+ ( width >> level as u32 ) . max ( 1 ) ,
133
+ ( height >> level as u32 ) . max ( 1 ) ,
134
+ ) ;
135
+ let ( num_blocks_x, num_blocks_y) = (
136
+ ( ( level_width + block_width_pixels - 1 ) / block_width_pixels) . max ( 1 ) ,
137
+ ( ( level_height + block_height_pixels - 1 ) / block_height_pixels) . max ( 1 ) ,
138
+ ) ;
139
+ let level_bytes = ( num_blocks_x * num_blocks_y * block_bytes) as usize ;
145
140
146
- // Next mip dimensions are half the current, minimum 1x1
147
- original_width = ( original_width / 2 ) . max ( 1 ) ;
148
- original_height = ( original_height / 2 ) . max ( 1 ) ;
141
+ let mut offset = 0 ;
142
+ for _layer in 0 ..layer_count {
143
+ for _face in 0 ..face_count {
144
+ // NOTE: SliceParametersUastc does not implement Clone nor Copy so
145
+ // it has to be created per use
146
+ let slice_parameters = SliceParametersUastc {
147
+ num_blocks_x,
148
+ num_blocks_y,
149
+ has_alpha : false ,
150
+ original_width : level_width,
151
+ original_height : level_height,
152
+ } ;
153
+ transcoder
154
+ . transcode_slice (
155
+ & level_data[ offset..( offset + level_bytes) ] ,
156
+ slice_parameters,
157
+ DecodeFlags :: HIGH_QUALITY ,
158
+ transcode_block_format,
159
+ )
160
+ . map ( |mut transcoded_level| transcoded[ level] . append ( & mut transcoded_level) )
161
+ . map_err ( |error| {
162
+ TextureError :: SuperDecompressionError ( format ! (
163
+ "Failed to transcode mip level {} from UASTC to {:?}: {:?}" ,
164
+ level, transcode_block_format, error
165
+ ) )
166
+ } ) ?;
167
+ offset += level_bytes;
168
+ }
169
+ }
149
170
}
150
171
texture_format
151
172
}
@@ -178,16 +199,52 @@ pub fn ktx2_buffer_to_image(
178
199
) ) ) ;
179
200
}
180
201
202
+ // Reorder data from KTX2 MipXLayerYFaceZ to wgpu LayerYFaceZMipX
203
+ let texture_format_info = texture_format. describe ( ) ;
204
+ let ( block_width_pixels, block_height_pixels) = (
205
+ texture_format_info. block_dimensions . 0 as usize ,
206
+ texture_format_info. block_dimensions . 1 as usize ,
207
+ ) ;
208
+ let block_bytes = texture_format_info. block_size as usize ;
209
+
210
+ let mut wgpu_data = vec ! [ Vec :: default ( ) ; ( layer_count * face_count) as usize ] ;
211
+ for ( level, level_data) in levels. iter ( ) . enumerate ( ) {
212
+ let ( level_width, level_height) = (
213
+ ( width as usize >> level) . max ( 1 ) ,
214
+ ( height as usize >> level) . max ( 1 ) ,
215
+ ) ;
216
+ let ( num_blocks_x, num_blocks_y) = (
217
+ ( ( level_width + block_width_pixels - 1 ) / block_width_pixels) . max ( 1 ) ,
218
+ ( ( level_height + block_height_pixels - 1 ) / block_height_pixels) . max ( 1 ) ,
219
+ ) ;
220
+ let level_bytes = num_blocks_x * num_blocks_y * block_bytes;
221
+
222
+ let mut index = 0 ;
223
+ for _layer in 0 ..layer_count {
224
+ for _face in 0 ..face_count {
225
+ let offset = index * level_bytes;
226
+ wgpu_data[ index] . extend_from_slice ( & level_data[ offset..( offset + level_bytes) ] ) ;
227
+ index += 1 ;
228
+ }
229
+ }
230
+ }
231
+
181
232
// Assign the data and fill in the rest of the metadata now the possible
182
233
// error cases have been handled
183
234
let mut image = Image :: default ( ) ;
184
235
image. texture_descriptor . format = texture_format;
185
- image. data = levels . into_iter ( ) . flatten ( ) . collect :: < Vec < _ > > ( ) ;
236
+ image. data = wgpu_data . into_iter ( ) . flatten ( ) . collect :: < Vec < _ > > ( ) ;
186
237
image. texture_descriptor . size = Extent3d {
187
238
width,
188
239
height,
189
- depth_or_array_layers : if layer_count > 1 { layer_count } else { depth } . max ( 1 ) ,
190
- } ;
240
+ depth_or_array_layers : if layer_count > 1 || face_count > 1 {
241
+ layer_count * face_count
242
+ } else {
243
+ depth
244
+ }
245
+ . max ( 1 ) ,
246
+ }
247
+ . physical_size ( texture_format) ;
191
248
image. texture_descriptor . mip_level_count = level_count;
192
249
image. texture_descriptor . dimension = if depth > 1 {
193
250
TextureDimension :: D3
@@ -196,6 +253,24 @@ pub fn ktx2_buffer_to_image(
196
253
} else {
197
254
TextureDimension :: D1
198
255
} ;
256
+ let mut dimension = None ;
257
+ if face_count == 6 {
258
+ dimension = Some ( if layer_count > 1 {
259
+ TextureViewDimension :: CubeArray
260
+ } else {
261
+ TextureViewDimension :: Cube
262
+ } ) ;
263
+ } else if layer_count > 1 {
264
+ dimension = Some ( TextureViewDimension :: D2Array ) ;
265
+ } else if depth > 1 {
266
+ dimension = Some ( TextureViewDimension :: D3 ) ;
267
+ }
268
+ if dimension. is_some ( ) {
269
+ image. texture_view_descriptor = Some ( TextureViewDescriptor {
270
+ dimension,
271
+ ..default ( )
272
+ } ) ;
273
+ }
199
274
Ok ( image)
200
275
}
201
276
0 commit comments