1use basis_universal_sys as sys;
2use std::ffi::CStr;
3
4#[derive(Copy, Clone, Debug, PartialEq)]
6#[repr(i32)]
7pub enum BasisTextureType {
8 TextureType2D = sys::basist_basis_texture_type_cBASISTexType2D,
10 TextureType2DArray = sys::basist_basis_texture_type_cBASISTexType2DArray,
12 TextureTypeCubemapArray = sys::basist_basis_texture_type_cBASISTexTypeCubemapArray,
14 TextureTypeVideoFrames = sys::basist_basis_texture_type_cBASISTexTypeVideoFrames,
16 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 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#[allow(non_camel_case_types)]
44#[derive(Copy, Clone, Debug, PartialEq)]
45#[repr(i32)]
46pub enum BasisTextureFormat {
47 ETC1S = sys::basist_basis_tex_format_cETC1S,
50
51 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 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#[allow(non_camel_case_types)]
82#[derive(Copy, Clone, Debug, PartialEq)]
83#[repr(i32)]
84pub enum TranscoderTextureFormat {
85 ETC1_RGB = sys::basist_transcoder_texture_format_cTFETC1_RGB,
87 ETC2_RGBA = sys::basist_transcoder_texture_format_cTFETC2_RGBA,
89
90 BC1_RGB = sys::basist_transcoder_texture_format_cTFBC1_RGB,
95 BC3_RGBA = sys::basist_transcoder_texture_format_cTFBC3_RGBA,
97 BC4_R = sys::basist_transcoder_texture_format_cTFBC4_R,
99 BC5_RG = sys::basist_transcoder_texture_format_cTFBC5_RG,
101 BC7_RGBA = sys::basist_transcoder_texture_format_cTFBC7_RGBA,
103
104 PVRTC1_4_RGB = sys::basist_transcoder_texture_format_cTFPVRTC1_4_RGB,
109 PVRTC1_4_RGBA = sys::basist_transcoder_texture_format_cTFPVRTC1_4_RGBA,
111
112 ASTC_4x4_RGBA = sys::basist_transcoder_texture_format_cTFASTC_4x4_RGBA,
117
118 ATC_RGB = sys::basist_transcoder_texture_format_cTFATC_RGB,
123 ATC_RGBA = sys::basist_transcoder_texture_format_cTFATC_RGBA,
125
126 FXT1_RGB = sys::basist_transcoder_texture_format_cTFFXT1_RGB,
133
134 PVRTC2_4_RGB = sys::basist_transcoder_texture_format_cTFPVRTC2_4_RGB,
136 PVRTC2_4_RGBA = sys::basist_transcoder_texture_format_cTFPVRTC2_4_RGBA,
138
139 ETC2_EAC_R11 = sys::basist_transcoder_texture_format_cTFETC2_EAC_R11,
141 ETC2_EAC_RG11 = sys::basist_transcoder_texture_format_cTFETC2_EAC_RG11,
143
144 RGBA32 = sys::basist_transcoder_texture_format_cTFRGBA32,
149 RGB565 = sys::basist_transcoder_texture_format_cTFRGB565,
151 BGR565 = sys::basist_transcoder_texture_format_cTFBGR565,
153 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 pub fn bytes_per_block_or_pixel(self) -> u32 {
173 unsafe { sys::basis_get_bytes_per_block_or_pixel(self.into()) }
174 }
175
176 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 pub fn has_alpha(self) -> bool {
186 unsafe { sys::basis_transcoder_format_has_alpha(self.into()) }
187 }
188
189 pub fn is_compressed(self) -> bool {
191 unsafe { !sys::basis_transcoder_format_is_uncompressed(self.into()) }
192 }
193
194 pub fn uncompressed_bytes_per_pixel(self) -> u32 {
196 unsafe { sys::basis_get_uncompressed_bytes_per_pixel(self.into()) }
197 }
198
199 pub fn block_width(self) -> u32 {
201 unsafe { sys::basis_get_block_width(self.into()) }
202 }
203
204 pub fn block_height(self) -> u32 {
206 unsafe { sys::basis_get_block_height(self.into()) }
207 }
208
209 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 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 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 let minimum_output_buffer_blocks_or_pixels = if !self.is_compressed() {
234 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 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 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 pub struct DecodeFlags: i32 {
309 const PVRTC_DECODE_TO_NEXT_POW_2 = sys::basist_basisu_decode_flags_cDecodeFlagsPVRTCDecodeToNextPow2;
311
312 const TRANSCODE_ALPHA_DATA_TO_OPAQUE_FORMATS = sys::basist_basisu_decode_flags_cDecodeFlagsTranscodeAlphaDataToOpaqueFormats;
315
316 const BC1_FORBID_THREE_COLOR_BLOCKS = sys::basist_basisu_decode_flags_cDecodeFlagsBC1ForbidThreeColorBlocks;
319
320 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#[allow(non_camel_case_types)]
330#[derive(Copy, Clone, Debug, PartialEq)]
331#[repr(i32)]
332pub enum TranscoderBlockFormat {
333 ETC1 = sys::basist_block_format_cETC1,
335 ETC2_RGBA = sys::basist_block_format_cETC2_RGBA,
337 BC1 = sys::basist_block_format_cBC1,
339 BC3 = sys::basist_block_format_cBC3,
341 BC4 = sys::basist_block_format_cBC4,
343 BC5 = sys::basist_block_format_cBC5,
345 PVRTC1_4_RGB = sys::basist_block_format_cPVRTC1_4_RGB,
347 PVRTC1_4_RGBA = sys::basist_block_format_cPVRTC1_4_RGBA,
349 BC7 = sys::basist_block_format_cBC7,
351 BC7_M5_COLOR = sys::basist_block_format_cBC7_M5_COLOR,
353 BC7_M5_ALPHA = sys::basist_block_format_cBC7_M5_ALPHA,
355 ETC2_EAC_A8 = sys::basist_block_format_cETC2_EAC_A8,
357 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 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 Indices = sys::basist_block_format_cIndices,
374
375 RGB32 = sys::basist_block_format_cRGB32,
377 RGBA32 = sys::basist_block_format_cRGBA32,
379 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 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 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 pub fn is_compressed(self) -> bool {
450 unsafe { !sys::basis_block_format_is_uncompressed(self.into()) }
451 }
452
453 pub fn block_width(self) -> u32 {
455 match self {
456 TranscoderBlockFormat::FXT1_RGB => 8,
457 _ => 4,
458 }
459 }
460
461 pub fn block_height(self) -> u32 {
463 4
464 }
465
466 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 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 if !self.is_compressed() {
484 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 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}