basis_universal/transcoding/
enums.rs

1use basis_universal_sys as sys;
2use std::ffi::CStr;
3
4/// The type of data stored
5#[derive(Copy, Clone, Debug, PartialEq)]
6#[repr(i32)]
7pub enum BasisTextureType {
8    /// An arbitrary array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image may have a different resolution and # of mipmap levels
9    TextureType2D = sys::basist_basis_texture_type_cBASISTexType2D,
10    /// An array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image has the same resolution and mipmap levels
11    TextureType2DArray = sys::basist_basis_texture_type_cBASISTexType2DArray,
12    /// an array of cubemap levels, total # of images must be divisable by 6, in X+, X-, Y+, Y-, Z+, Z- order, with optional mipmaps
13    TextureTypeCubemapArray = sys::basist_basis_texture_type_cBASISTexTypeCubemapArray,
14    /// An array of 2D video frames, with optional mipmaps, # frames = # images, each image has the same resolution and # of mipmap levels
15    TextureTypeVideoFrames = sys::basist_basis_texture_type_cBASISTexTypeVideoFrames,
16    /// A 3D texture with optional mipmaps, Z dimension = # images, each image has the same resolution and # of mipmap levels
17    TextureTypeVolume = sys::basist_basis_texture_type_cBASISTexTypeVolume,
18}
19
20impl Into<sys::basist_basis_texture_type> for BasisTextureType {
21    fn into(self) -> sys::basist_basis_texture_type {
22        self as sys::basist_basis_texture_type
23    }
24}
25
26impl From<sys::basist_basis_texture_type> for BasisTextureType {
27    fn from(value: sys::basist_basis_texture_type) -> Self {
28        unsafe { std::mem::transmute(value as u32) }
29    }
30}
31
32impl BasisTextureType {
33    /// Returns the texture type's name in ASCII.
34    pub fn texture_type_name(self) -> &'static str {
35        unsafe {
36            let value = sys::basis_get_texture_type_name(self.into());
37            CStr::from_ptr(value).to_str().unwrap()
38        }
39    }
40}
41
42/// The compression mode/format to use
43#[allow(non_camel_case_types)]
44#[derive(Copy, Clone, Debug, PartialEq)]
45#[repr(i32)]
46pub enum BasisTextureFormat {
47    /// A lower quality mode which is based off a subset of ETC1 called "ETC1S". Includes built-in
48    /// data compression
49    ETC1S = sys::basist_basis_tex_format_cETC1S,
50
51    /// Enable UASTC compression mode instead of the default ETC1S mode. Significantly higher
52    /// texture quality, but larger files. UASTC supports an optional Rate Distortion Optimization
53    /// (RDO) post-process stage that conditions the encoded UASTC texture data in the .basis file
54    /// so it can be more effectively LZ compressed by the end user.
55    UASTC4x4 = sys::basist_basis_tex_format_cUASTC4x4,
56}
57
58impl Into<sys::basist_basis_tex_format> for BasisTextureFormat {
59    fn into(self) -> sys::basist_basis_tex_format {
60        self as sys::basist_basis_tex_format
61    }
62}
63
64impl From<sys::basist_basis_tex_format> for BasisTextureFormat {
65    fn from(value: sys::basist_basis_tex_format) -> Self {
66        unsafe { std::mem::transmute(value as i32) }
67    }
68}
69
70impl BasisTextureFormat {
71    /// Returns true if the specified format was enabled at compile time.
72    pub fn can_transcode_to_format(
73        self,
74        transcoder_texture_format: TranscoderTextureFormat,
75    ) -> bool {
76        unsafe { sys::basis_is_format_supported(transcoder_texture_format.into(), self.into()) }
77    }
78}
79
80/// The texture format to transcode basis-universal data into
81#[allow(non_camel_case_types)]
82#[derive(Copy, Clone, Debug, PartialEq)]
83#[repr(i32)]
84pub enum TranscoderTextureFormat {
85    /// Opaque only, returns RGB or alpha data if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
86    ETC1_RGB = sys::basist_transcoder_texture_format_cTFETC1_RGB,
87    /// Opaque+alpha, ETC2_EAC_A8 block followed by a ETC1 block, alpha channel will be opaque for opaque .basis files
88    ETC2_RGBA = sys::basist_transcoder_texture_format_cTFETC2_RGBA,
89
90    //
91    // BC1-5, BC7 (desktop, some mobile devices)
92    //
93    /// Opaque only, no punchthrough alpha support yet, transcodes alpha slice if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
94    BC1_RGB = sys::basist_transcoder_texture_format_cTFBC1_RGB,
95    /// Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
96    BC3_RGBA = sys::basist_transcoder_texture_format_cTFBC3_RGBA,
97    /// Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
98    BC4_R = sys::basist_transcoder_texture_format_cTFBC4_R,
99    /// XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
100    BC5_RG = sys::basist_transcoder_texture_format_cTFBC5_RG,
101    /// RGB or RGBA, mode 5 for ETC1S, modes (1,2,3,5,6,7) for UASTC
102    BC7_RGBA = sys::basist_transcoder_texture_format_cTFBC7_RGBA,
103
104    //
105    // PVRTC1 4bpp (mobile, PowerVR devices)
106    //
107    /// Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
108    PVRTC1_4_RGB = sys::basist_transcoder_texture_format_cTFPVRTC1_4_RGB,
109    /// Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
110    PVRTC1_4_RGBA = sys::basist_transcoder_texture_format_cTFPVRTC1_4_RGBA,
111
112    //
113    // ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
114    //
115    /// Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
116    ASTC_4x4_RGBA = sys::basist_transcoder_texture_format_cTFASTC_4x4_RGBA,
117
118    //
119    // ATC (mobile, Adreno devices, this is a niche format)
120    //
121    /// Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD)
122    ATC_RGB = sys::basist_transcoder_texture_format_cTFATC_RGB,
123    /// Opaque+alpha, alpha channel will be opaque for opaque .basis files. ATI ATC (GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD)
124    ATC_RGBA = sys::basist_transcoder_texture_format_cTFATC_RGBA,
125
126    //
127    // FXT1 (desktop, Intel devices, this is a super obscure format)
128    //
129    /// Opaque only, uses exclusively CC_MIXED blocks. Notable for having a 8x4 block size. GL_3DFX_texture_compression_FXT1 is supported on Intel integrated GPU's (such as HD 630).
130    /// Punch-through alpha is relatively easy to support, but full alpha is harder. This format is only here for completeness so opaque-only is fine for now.
131    /// See the BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING macro in basisu_transcoder_internal.h.
132    FXT1_RGB = sys::basist_transcoder_texture_format_cTFFXT1_RGB,
133
134    /// Opaque-only, almost BC1 quality, much faster to transcode and supports arbitrary texture dimensions (unlike PVRTC1 RGB).
135    PVRTC2_4_RGB = sys::basist_transcoder_texture_format_cTFPVRTC2_4_RGB,
136    /// Opaque+alpha, slower to encode than cTFPVRTC2_4_RGB. Premultiplied alpha is highly recommended, otherwise the color channel can leak into the alpha channel on transparent blocks.
137    PVRTC2_4_RGBA = sys::basist_transcoder_texture_format_cTFPVRTC2_4_RGBA,
138
139    /// R only (ETC2 EAC R11 unsigned)
140    ETC2_EAC_R11 = sys::basist_transcoder_texture_format_cTFETC2_EAC_R11,
141    /// RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
142    ETC2_EAC_RG11 = sys::basist_transcoder_texture_format_cTFETC2_EAC_RG11,
143
144    //
145    // Uncompressed (raw pixel) formats
146    //
147    /// 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
148    RGBA32 = sys::basist_transcoder_texture_format_cTFRGBA32,
149    /// 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11
150    RGB565 = sys::basist_transcoder_texture_format_cTFRGB565,
151    /// 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
152    BGR565 = sys::basist_transcoder_texture_format_cTFBGR565,
153    /// 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
154    RGBA4444 = sys::basist_transcoder_texture_format_cTFRGBA4444,
155}
156
157impl Into<sys::basist_transcoder_texture_format> for TranscoderTextureFormat {
158    fn into(self) -> sys::basist_transcoder_texture_format {
159        self as sys::basist_transcoder_texture_format
160    }
161}
162
163impl From<sys::basist_transcoder_texture_format> for TranscoderTextureFormat {
164    fn from(value: sys::basist_transcoder_texture_format) -> Self {
165        unsafe { std::mem::transmute(value as i32) }
166    }
167}
168
169impl TranscoderTextureFormat {
170    /// For compressed texture formats, this returns the # of bytes per block. For uncompressed, it returns the # of bytes per pixel.
171    /// NOTE: Previously, this function was called basis_get_bytes_per_block(), and it always returned 16*bytes_per_pixel for uncompressed formats which was confusing.
172    pub fn bytes_per_block_or_pixel(self) -> u32 {
173        unsafe { sys::basis_get_bytes_per_block_or_pixel(self.into()) }
174    }
175
176    /// Returns format's name in ASCII
177    pub fn format_name(self) -> &'static str {
178        unsafe {
179            let value = sys::basis_get_format_name(self.into());
180            CStr::from_ptr(value).to_str().unwrap()
181        }
182    }
183
184    /// Returns true if the format supports an alpha channel.
185    pub fn has_alpha(self) -> bool {
186        unsafe { sys::basis_transcoder_format_has_alpha(self.into()) }
187    }
188
189    /// Returns true if the transcoder texture type is a compressed format.
190    pub fn is_compressed(self) -> bool {
191        unsafe { !sys::basis_transcoder_format_is_uncompressed(self.into()) }
192    }
193
194    /// Returns the # of bytes per pixel for uncompressed formats, or 0 for block texture formats.
195    pub fn uncompressed_bytes_per_pixel(self) -> u32 {
196        unsafe { sys::basis_get_uncompressed_bytes_per_pixel(self.into()) }
197    }
198
199    /// Returns the block width for the specified texture format, which is currently either 4 or 8 for FXT1.
200    pub fn block_width(self) -> u32 {
201        unsafe { sys::basis_get_block_width(self.into()) }
202    }
203
204    /// Returns the block height for the specified texture format, which is currently always 4.
205    pub fn block_height(self) -> u32 {
206        unsafe { sys::basis_get_block_height(self.into()) }
207    }
208
209    /// Returns true if the specified format was enabled at compile time.
210    pub fn can_transcode_from_format(
211        self,
212        basis_texture_format: BasisTextureFormat,
213    ) -> bool {
214        basis_texture_format.can_transcode_to_format(self)
215    }
216
217    /// Calculate the minimum output buffer required to store transcoded data in blocks for
218    /// compressed formats and pixels for uncompressed formats
219    pub fn calculate_minimum_output_buffer_blocks_or_pixels(
220        self,
221        original_width: u32,
222        original_height: u32,
223        total_slice_blocks: u32,
224        output_row_pitch_in_blocks_or_pixels: Option<u32>,
225        output_rows_in_pixels: Option<u32>,
226    ) -> u32 {
227        // Default of 0 is fine for these values
228        let mut output_row_pitch_in_blocks_or_pixels =
229            output_row_pitch_in_blocks_or_pixels.unwrap_or(0);
230        let mut output_rows_in_pixels = output_rows_in_pixels.unwrap_or(0);
231
232        // Derived from implementation of basis_validate_output_buffer_size
233        let minimum_output_buffer_blocks_or_pixels = if !self.is_compressed() {
234            // Assume the output buffer is orig_width by orig_height
235            if output_row_pitch_in_blocks_or_pixels == 0 {
236                output_row_pitch_in_blocks_or_pixels = original_width;
237            }
238
239            if output_rows_in_pixels == 0 {
240                output_rows_in_pixels = original_height;
241            }
242
243            output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels
244        } else if self == TranscoderTextureFormat::FXT1_RGB {
245            let num_blocks_fxt1_x = (original_width + 7) / 8;
246            let num_blocks_fxt1_y = (original_height + 3) / 4;
247            num_blocks_fxt1_x * num_blocks_fxt1_y
248        } else {
249            total_slice_blocks
250        };
251
252        debug_assert!(self.validate_output_buffer_size(
253            minimum_output_buffer_blocks_or_pixels,
254            original_width,
255            original_height,
256            total_slice_blocks,
257            Some(output_row_pitch_in_blocks_or_pixels),
258            Some(output_rows_in_pixels),
259        ));
260
261        minimum_output_buffer_blocks_or_pixels
262    }
263
264    /// Calculate the minimum output buffer required to store transcoded data in bytes
265    pub fn calculate_minimum_output_buffer_bytes(
266        self,
267        original_width: u32,
268        original_height: u32,
269        total_slice_blocks: u32,
270        output_row_pitch_in_blocks_or_pixels: Option<u32>,
271        output_rows_in_pixels: Option<u32>,
272    ) -> u32 {
273        self.calculate_minimum_output_buffer_blocks_or_pixels(
274            original_width,
275            original_height,
276            total_slice_blocks,
277            output_row_pitch_in_blocks_or_pixels,
278            output_rows_in_pixels,
279        ) * self.bytes_per_block_or_pixel()
280    }
281
282    /// Verify that the buffer size is large enough for the transcoded data
283    pub fn validate_output_buffer_size(
284        self,
285        output_blocks_buf_size_in_blocks_or_pixels: u32,
286        original_width: u32,
287        original_height: u32,
288        total_slice_blocks: u32,
289        output_row_pitch_in_blocks_or_pixels: Option<u32>,
290        output_rows_in_pixels: Option<u32>,
291    ) -> bool {
292        unsafe {
293            sys::basis_validate_output_buffer_size(
294                self.into(),
295                output_blocks_buf_size_in_blocks_or_pixels,
296                original_width,
297                original_height,
298                output_row_pitch_in_blocks_or_pixels.unwrap_or(0),
299                output_rows_in_pixels.unwrap_or(0),
300                total_slice_blocks,
301            )
302        }
303    }
304}
305
306bitflags::bitflags! {
307    /// Flags that affect transcoding
308    pub struct DecodeFlags: i32 {
309        /// PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
310        const PVRTC_DECODE_TO_NEXT_POW_2 = sys::basist_basisu_decode_flags_cDecodeFlagsPVRTCDecodeToNextPow2;
311
312        /// When decoding to an opaque texture format, if the basis file has alpha, decode the alpha slice instead of the color slice to the output texture format.
313        /// This is primarily to allow decoding of textures with alpha to multiple ETC1 textures (one for color, another for alpha).
314        const TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS = sys::basist_basisu_decode_flags_cDecodeFlagsTranscodeAlphaDataToOpaqueFormats;
315
316        /// Forbid usage of BC1 3 color blocks (we don't support BC1 punchthrough alpha yet).
317        /// This flag is used internally when decoding to BC3.
318        const BC1_FORBID_THREE_COLOR_BLOCKS = sys::basist_basisu_decode_flags_cDecodeFlagsBC1ForbidThreeColorBlocks;
319
320        /// The output buffer contains alpha endpoint/selector indices.
321        /// Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
322        const OUTPUT_HAS_ALPHA_INDICES = sys::basist_basisu_decode_flags_cDecodeFlagsOutputHasAlphaIndices;
323
324        const HIGH_QUALITY = sys::basist_basisu_decode_flags_cDecodeFlagsHighQuality;
325    }
326}
327
328/// The block format to transcode universal texture data into
329#[allow(non_camel_case_types)]
330#[derive(Copy, Clone, Debug, PartialEq)]
331#[repr(i32)]
332pub enum TranscoderBlockFormat {
333    /// ETC1S RGB
334    ETC1 = sys::basist_block_format_cETC1,
335    /// full ETC2 EAC RGBA8 block
336    ETC2_RGBA = sys::basist_block_format_cETC2_RGBA,
337    /// DXT1 RGB
338    BC1 = sys::basist_block_format_cBC1,
339    /// BC4 block followed by a four color BC1 block
340    BC3 = sys::basist_block_format_cBC3,
341    /// DXT5A (alpha block only)
342    BC4 = sys::basist_block_format_cBC4,
343    /// two BC4 blocks
344    BC5 = sys::basist_block_format_cBC5,
345    /// opaque-only PVRTC1 4bpp
346    PVRTC1_4_RGB = sys::basist_block_format_cPVRTC1_4_RGB,
347    /// PVRTC1 4bpp RGBA
348    PVRTC1_4_RGBA = sys::basist_block_format_cPVRTC1_4_RGBA,
349    /// Full BC7 block, any mode
350    BC7 = sys::basist_block_format_cBC7,
351    /// RGB BC7 mode 5 color (writes an opaque mode 5 block)
352    BC7_M5_COLOR = sys::basist_block_format_cBC7_M5_COLOR,
353    /// alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.)
354    BC7_M5_ALPHA = sys::basist_block_format_cBC7_M5_ALPHA,
355    /// alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format)
356    ETC2_EAC_A8 = sys::basist_block_format_cETC2_EAC_A8,
357    /// ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC
358    /// data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking.
359    ASTC_4x4 = sys::basist_block_format_cASTC_4x4,
360
361    ATC_RGB = sys::basist_block_format_cATC_RGB,
362    ATC_RGBA_INTERPOLATED_ALPHA = sys::basist_block_format_cATC_RGBA_INTERPOLATED_ALPHA,
363    /// Opaque-only, has oddball 8x4 pixel block size
364    FXT1_RGB = sys::basist_block_format_cFXT1_RGB,
365
366    PVRTC2_4_RGB = sys::basist_block_format_cPVRTC2_4_RGB,
367    PVRTC2_4_RGBA = sys::basist_block_format_cPVRTC2_4_RGBA,
368
369    ETC2_EAC_R11 = sys::basist_block_format_cETC2_EAC_R11,
370    ETC2_EAC_RG11 = sys::basist_block_format_cETC2_EAC_RG11,
371
372    /// Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits)
373    Indices = sys::basist_block_format_cIndices,
374
375    /// Writes RGB components to 32bpp output pixels
376    RGB32 = sys::basist_block_format_cRGB32,
377    /// Writes RGB255 components to 32bpp output pixels
378    RGBA32 = sys::basist_block_format_cRGBA32,
379    /// Writes alpha component to 32bpp output pixels
380    A32 = sys::basist_block_format_cA32,
381
382    RGB565 = sys::basist_block_format_cRGB565,
383    BGR565 = sys::basist_block_format_cBGR565,
384
385    RGBA4444_COLOR = sys::basist_block_format_cRGBA4444_COLOR,
386    RGBA4444_ALPHA = sys::basist_block_format_cRGBA4444_ALPHA,
387    RGBA4444_COLOR_OPAQUE = sys::basist_block_format_cRGBA4444_COLOR_OPAQUE,
388    RGBA4444 = sys::basist_block_format_cRGBA4444,
389}
390
391impl Into<sys::basist_block_format> for TranscoderBlockFormat {
392    fn into(self) -> sys::basist_block_format {
393        self as sys::basist_block_format
394    }
395}
396
397impl From<sys::basist_block_format> for TranscoderBlockFormat {
398    fn from(value: sys::basist_block_format) -> Self {
399        unsafe { std::mem::transmute(value as i32) }
400    }
401}
402
403impl TranscoderBlockFormat {
404    /// For compressed texture formats, this returns the # of bytes per block. For uncompressed, it returns the # of bytes per pixel.
405    pub fn bytes_per_block_or_pixel(self) -> u32 {
406        match self {
407            TranscoderBlockFormat::ETC1 => 8,
408            TranscoderBlockFormat::ETC2_RGBA => 16,
409            TranscoderBlockFormat::BC1 => 8,
410            TranscoderBlockFormat::BC3 => 16,
411            TranscoderBlockFormat::BC4 => 8,
412            TranscoderBlockFormat::BC5 => 16,
413            TranscoderBlockFormat::PVRTC1_4_RGB => 8,
414            TranscoderBlockFormat::PVRTC1_4_RGBA => 8,
415            TranscoderBlockFormat::BC7 => 16,
416            TranscoderBlockFormat::BC7_M5_COLOR => 16,
417            TranscoderBlockFormat::BC7_M5_ALPHA => 16,
418            TranscoderBlockFormat::ETC2_EAC_A8 => 8,
419            TranscoderBlockFormat::ASTC_4x4 => 16,
420            TranscoderBlockFormat::ATC_RGB => 8,
421            TranscoderBlockFormat::ATC_RGBA_INTERPOLATED_ALPHA => 16,
422            TranscoderBlockFormat::FXT1_RGB => 8,
423            TranscoderBlockFormat::PVRTC2_4_RGB => 8,
424            TranscoderBlockFormat::PVRTC2_4_RGBA => 8,
425            TranscoderBlockFormat::ETC2_EAC_R11 => 8,
426            TranscoderBlockFormat::ETC2_EAC_RG11 => 16,
427            TranscoderBlockFormat::Indices => 2,
428            TranscoderBlockFormat::RGB32 => 4,
429            TranscoderBlockFormat::RGBA32 => 4,
430            TranscoderBlockFormat::A32 => 4,
431            TranscoderBlockFormat::RGB565 => 2,
432            TranscoderBlockFormat::BGR565 => 2,
433            TranscoderBlockFormat::RGBA4444_COLOR => 2,
434            TranscoderBlockFormat::RGBA4444_ALPHA => 2,
435            TranscoderBlockFormat::RGBA4444_COLOR_OPAQUE => 2,
436            TranscoderBlockFormat::RGBA4444 => 2,
437        }
438    }
439
440    /// Returns format's name in ASCII
441    pub fn format_name(self) -> &'static str {
442        unsafe {
443            let value = sys::basis_get_block_format_name(self.into());
444            CStr::from_ptr(value).to_str().unwrap()
445        }
446    }
447
448    /// Returns true if the block format is a compressed format.
449    pub fn is_compressed(self) -> bool {
450        unsafe { !sys::basis_block_format_is_uncompressed(self.into()) }
451    }
452
453    /// Returns the block width for the specified texture format, which is currently either 4 or 8 for FXT1.
454    pub fn block_width(self) -> u32 {
455        match self {
456            TranscoderBlockFormat::FXT1_RGB => 8,
457            _ => 4,
458        }
459    }
460
461    /// Returns the block height for the specified texture format, which is currently always 4.
462    pub fn block_height(self) -> u32 {
463        4
464    }
465
466    /// Calculate the minimum output buffer required to store transcoded data in blocks for
467    /// compressed formats and pixels for uncompressed formats
468    pub fn calculate_minimum_output_buffer_blocks_or_pixels(
469        self,
470        original_width: u32,
471        original_height: u32,
472        total_slice_blocks: u32,
473        output_row_pitch_in_blocks_or_pixels: Option<u32>,
474        output_rows_in_pixels: Option<u32>,
475    ) -> u32 {
476        // Default of 0 is fine for these values
477        let mut output_row_pitch_in_blocks_or_pixels =
478            output_row_pitch_in_blocks_or_pixels.unwrap_or(0);
479        let mut output_rows_in_pixels = output_rows_in_pixels.unwrap_or(0);
480
481        // Derived from implementation of basis_validate_output_buffer_size
482
483        if !self.is_compressed() {
484            // Assume the output buffer is orig_width by orig_height
485            if output_row_pitch_in_blocks_or_pixels == 0 {
486                output_row_pitch_in_blocks_or_pixels = original_width;
487            }
488
489            if output_rows_in_pixels == 0 {
490                output_rows_in_pixels = original_height;
491            }
492
493            output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels
494        } else if self == TranscoderBlockFormat::FXT1_RGB {
495            let num_blocks_fxt1_x = (original_width + 7) / 8;
496            let num_blocks_fxt1_y = (original_height + 3) / 4;
497            num_blocks_fxt1_x * num_blocks_fxt1_y
498        } else {
499            total_slice_blocks
500        }
501    }
502
503    /// Calculate the minimum output buffer required to store transcoded data in bytes
504    pub fn calculate_minimum_output_buffer_bytes(
505        self,
506        original_width: u32,
507        original_height: u32,
508        total_slice_blocks: u32,
509        output_row_pitch_in_blocks_or_pixels: Option<u32>,
510        output_rows_in_pixels: Option<u32>,
511    ) -> u32 {
512        self.calculate_minimum_output_buffer_blocks_or_pixels(
513            original_width,
514            original_height,
515            total_slice_blocks,
516            output_row_pitch_in_blocks_or_pixels,
517            output_rows_in_pixels,
518        ) * self.bytes_per_block_or_pixel()
519    }
520}