basis_universal/encoding/
compressor_params.rs

1use super::*;
2use crate::{BasisTextureFormat, UserData};
3use basis_universal_sys as sys;
4pub use basis_universal_sys::ColorU8;
5
6/// The color space the image to be compressed is encoded in. Using the correct color space will
7#[derive(Debug, Copy, Clone)]
8pub enum ColorSpace {
9    /// Used for normal maps or other "data" images
10    Linear,
11
12    /// Used for color maps and other "visual" images
13    Srgb,
14}
15
16/// Parameters that are used to configure a [Compressor]
17pub struct CompressorParams(pub *mut sys::CompressorParams);
18
19impl Default for CompressorParams {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl CompressorParams {
26    /// Create a compressor with default options
27    pub fn new() -> Self {
28        unsafe {
29            let mut params = CompressorParams(sys::compressor_params_new());
30            params.set_default_options();
31            params
32        }
33    }
34
35    /// Resets the compressor params to default state
36    pub fn reset(&mut self) {
37        unsafe {
38            sys::compressor_params_clear(self.0);
39            self.set_default_options();
40            self.clear_source_image_list();
41        }
42    }
43
44    // The default options that are applied when creating a new compressor or calling reset() on it
45    fn set_default_options(&mut self) {
46        // Set a default quality level. Leaving this unset results in undefined behavior, so we set
47        // it to a working value by default
48        self.set_etc1s_quality_level(crate::ETC1S_QUALITY_DEFAULT);
49        self.set_uastc_quality_level(crate::UASTC_QUALITY_DEFAULT);
50
51        // The library by default prints to stdout, but since this is a library we should disable
52        // that by default
53        self.set_print_status_to_stdout(false);
54    }
55
56    //
57    // These function are used to load image data into the compressor
58    //
59
60    /// Get a reference to the source index. The internal list of source images is resized as needed
61    /// such that the image will exist
62    pub fn source_image_mut(
63        &mut self,
64        image_index: u32,
65    ) -> CompressorImageRef {
66        unsafe {
67            CompressorImageRef(sys::compressor_params_get_or_create_source_image(
68                self.0,
69                image_index,
70            ))
71        }
72    }
73
74    /// Resizes the source image list. If the provided length is shorter than the list, the data
75    /// beyond the provided length is truncated.
76    pub fn resize_source_image_list(
77        &mut self,
78        size: u32,
79    ) {
80        unsafe {
81            sys::compressor_params_resize_source_image_list(self.0, size as _);
82        }
83    }
84
85    /// Resets the image list to be zero-length
86    pub fn clear_source_image_list(&mut self) {
87        unsafe {
88            sys::compressor_params_clear_source_image_list(self.0);
89        }
90    }
91
92    /// Get a reference to the source index. The internal list of source images is resized as needed
93    /// such that the image will exist
94    pub fn source_mipmap_image_mut(
95        &mut self,
96        image_index: u32,
97        level: u32,
98    ) -> CompressorImageRef {
99        unsafe {
100            CompressorImageRef(sys::compressor_params_get_or_create_source_mipmap_image(
101                self.0,
102                image_index,
103                level,
104            ))
105        }
106    }
107
108    /// Resizes the source image list. If the provided length is shorter than the list, the data
109    /// beyond the provided length is truncated.
110    pub fn resize_source_mipmap_image_list(
111        &mut self,
112        size: u32,
113    ) {
114        unsafe {
115            sys::compressor_params_resize_source_mipmap_image_list(self.0, size as _);
116        }
117    }
118
119    /// Resizes the source image list. If the provided length is shorter than the list, the data
120    /// beyond the provided length is truncated.
121    pub fn resize_source_mipmap_level_image_list(
122        &mut self,
123        level: u32,
124        size: u32,
125    ) {
126        unsafe {
127            sys::compressor_params_resize_source_mipmap_image_level_list(
128                self.0, level as _, size as _,
129            );
130        }
131    }
132
133    /// Resets the image list to be zero-length
134    pub fn clear_source_mipmap_image_list(&mut self) {
135        unsafe {
136            sys::compressor_params_clear_source_mipmap_image_list(self.0);
137        }
138    }
139    //
140    // These set parameters for compression
141    //
142
143    /// Enable stdout logging
144    pub fn set_print_status_to_stdout(
145        &mut self,
146        print_status_to_stdout: bool,
147    ) {
148        unsafe { sys::compressor_params_set_status_output(self.0, print_status_to_stdout) }
149    }
150
151    /// Set ETC1S quality level. The value MUST be >= [ETC1S_QUALITY_MIN](crate::ETC1S_QUALITY_MIN)
152    /// and <= [ETC1S_QUALITY_MAX](crate::ETC1S_QUALITY_MAX).
153    pub fn set_etc1s_quality_level(
154        &mut self,
155        quality_level: u32,
156    ) {
157        assert!(quality_level >= crate::ETC1S_QUALITY_MIN);
158        assert!(quality_level <= crate::ETC1S_QUALITY_MAX);
159
160        unsafe {
161            sys::compressor_params_set_quality_level(self.0, quality_level as i32);
162        }
163    }
164
165    /// Sets UASTC quality level. The value MUST be >= [UASTC_QUALITY_MIN](crate::UASTC_QUALITY_MIN)
166    /// and <= [UASTC_QUALITY_MAX](crate::UASTC_QUALITY_MAX).
167    pub fn set_uastc_quality_level(
168        &mut self,
169        quality_level: u32,
170    ) {
171        assert!(quality_level >= crate::UASTC_QUALITY_MIN);
172        assert!(quality_level <= crate::UASTC_QUALITY_MAX);
173
174        unsafe {
175            let mut flags = sys::compressor_params_get_pack_uastc_flags(self.0);
176            flags |= quality_level as i32; // bindgen reflects constants as signed integers. So even if it doesn't make sense for the quality level to be signed, it has to be.
177            sys::compressor_params_set_pack_uastc_flags(self.0, flags);
178        }
179    }
180
181    /// Set the basis format we will compress to. See basis documentation for details. This
182    /// corresponds to the -uastc flag in the basisu command line tool and the m_uastc boolean param
183    /// on `basis_compressor_params` in the original library
184    ///
185    /// UASTC encoding result in significantly higher texture quality, but larger files.
186    pub fn set_basis_format(
187        &mut self,
188        basis_format: BasisTextureFormat,
189    ) {
190        let is_uastc = match basis_format {
191            BasisTextureFormat::ETC1S => false,
192            BasisTextureFormat::UASTC4x4 => true,
193        };
194
195        unsafe {
196            sys::compressor_params_set_uastc(self.0, is_uastc);
197        }
198    }
199
200    /// Sets the color space the images to be compressed is encoded in
201    ///
202    /// Setting a linear color space will:
203    /// * Use linear colorspace metrics (instead of the default sRGB)
204    /// * By default use linear (not sRGB) mipmap filtering
205    pub fn set_color_space(
206        &mut self,
207        color_space: ColorSpace,
208    ) {
209        let perceptual = match color_space {
210            ColorSpace::Linear => false,
211            ColorSpace::Srgb => true,
212        };
213        unsafe {
214            sys::compressor_params_set_perceptual(self.0, perceptual);
215        }
216    }
217
218    /// Override the mipmap generation color space behavior. This function is not necessary to call
219    /// if you call [set_color_space] with the correct value.
220    ///
221    /// * If the color space is sRGB, convert image to linear before filtering, then back to sRGB
222    /// * If the color space is linear, we keep the image in linear during mipmap filtering
223    ///   (i.e. do not convert to/from sRGB for filtering purposes)
224    pub fn set_mip_color_space(
225        &mut self,
226        color_space: ColorSpace,
227    ) {
228        let mip_srgb = match color_space {
229            ColorSpace::Linear => false,
230            ColorSpace::Srgb => true,
231        };
232        unsafe {
233            sys::compressor_params_set_mip_srgb(self.0, mip_srgb);
234        }
235    }
236
237    /// Disable backend's selector rate distortion optimizations (slightly faster, less noisy
238    /// output, but lower quality per output bit)
239    pub fn set_no_selector_rdo(
240        &mut self,
241        no_selector_rdo: bool,
242    ) {
243        unsafe {
244            sys::compressor_params_set_no_selector_rdo(self.0, no_selector_rdo);
245        }
246    }
247
248    /// Disable backend's endpoint rate distortion optimizations (slightly faster, less noisy
249    /// output, but lower quality per output bit)
250    pub fn set_no_endpoint_rdo(
251        &mut self,
252        no_endpoint_rdo: bool,
253    ) {
254        unsafe {
255            sys::compressor_params_set_no_endpoint_rdo(self.0, no_endpoint_rdo);
256        }
257    }
258
259    /// Enable/disable UASTC RDO post-processing and set UASTC RDO quality scalar to X. Lower
260    /// values=higher quality/larger LZ compressed files, higher values=lower quality/smaller LZ
261    /// compressed files. Good range to try is [.2-4]
262    pub fn set_rdo_uastc(
263        &mut self,
264        rdo_uastc_quality_scalar: Option<f32>,
265    ) {
266        unsafe {
267            match rdo_uastc_quality_scalar {
268                Some(quality_scalar) => {
269                    sys::compressor_params_set_rdo_uastc(self.0, true);
270                    sys::compressor_params_set_rdo_uastc_quality_scalar(self.0, quality_scalar);
271                }
272                None => {
273                    sys::compressor_params_set_rdo_uastc(self.0, false);
274                }
275            }
276        }
277    }
278
279    /// Generate mipmaps for each source image
280    ///
281    /// By default, sRGB textures will be converted from sRGB to linear before mipmap filtering.
282    /// This can be changed by calling [set_color_space] or [set_mip_color_space]
283    pub fn set_generate_mipmaps(
284        &mut self,
285        generate_mipmaps: bool,
286    ) {
287        unsafe {
288            sys::compressor_params_set_generate_mipmaps(self.0, generate_mipmaps);
289        }
290    }
291
292    /// Sets the smallest dimension mipmap that will be generated
293    pub fn set_mipmap_smallest_dimension(
294        &mut self,
295        smallest_dimension: u32,
296    ) {
297        unsafe {
298            sys::compressor_params_set_mip_smallest_dimension(self.0, smallest_dimension as _);
299        }
300    }
301
302    /// Set arbitrary userdata to be included with the basis-universal binary data
303    pub fn set_userdata(
304        &mut self,
305        userdata: UserData,
306    ) {
307        unsafe {
308            sys::compressor_params_set_userdata(self.0, userdata.userdata0, userdata.userdata1);
309        }
310    }
311
312    /// The `basisu` command line compressor offers a -normal_map parameter that sets several
313    /// values automatically. This convenience function mimics that parameter.
314    ///
315    /// * linear colorspace metrics
316    /// * linear mipmap filtering
317    /// * no selector RDO
318    /// * no sRGB
319    pub fn tune_for_normal_maps(&mut self) {
320        //TODO
321        unsafe {
322            sys::compressor_params_set_perceptual(self.0, false);
323            sys::compressor_params_set_mip_srgb(self.0, false);
324            sys::compressor_params_set_no_selector_rdo(self.0, true);
325            sys::compressor_params_set_no_endpoint_rdo(self.0, true);
326        }
327    }
328
329    // set_multithreaded not implemented here as this is controlled by thread count passed to
330    // `Compressor::new()`
331}
332
333impl Drop for CompressorParams {
334    fn drop(&mut self) {
335        unsafe {
336            sys::compressor_params_delete(self.0);
337        }
338    }
339}