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}