1#![allow(unreachable_code)] use std::borrow::Cow;
116use std::fmt;
117use std::error::Error;
118
119use crate::image_format::FormatNotSupportedError;
120
121pub use crate::image_format::{ClientFormat, TextureFormat};
122pub use crate::image_format::{UncompressedFloatFormat, UncompressedIntFormat, UncompressedUintFormat};
123pub use crate::image_format::{CompressedFormat, DepthFormat, DepthStencilFormat, StencilFormat};
124pub use crate::image_format::{CompressedSrgbFormat, SrgbFormat};
125pub use self::any::{TextureAny, TextureAnyMipmap, TextureAnyLayer, TextureAnyLayerMipmap};
126pub use self::any::{TextureAnyImage, Dimensions};
127pub use self::bindless::{ResidentTexture, TextureHandle, BindlessTexturesNotSupportedError};
128pub use self::get_format::{InternalFormat, InternalFormatType, GetFormatError};
129pub use self::pixel::PixelValue;
130pub use self::ty_support::{is_texture_1d_supported, is_texture_2d_supported};
131pub use self::ty_support::{is_texture_3d_supported, is_texture_1d_array_supported};
132pub use self::ty_support::{is_texture_2d_array_supported, is_texture_2d_multisample_supported};
133pub use self::ty_support::{is_texture_2d_multisample_array_supported, is_cubemaps_supported};
134pub use self::ty_support::is_cubemap_arrays_supported;
135pub use self::texture_import::ExternalTilingMode;
136pub use self::texture_import::ImportParameters;
137pub use self::texture_import::TextureImportError;
138
139pub mod bindless;
140pub mod buffer_texture;
141pub mod pixel_buffer;
142
143mod any;
144mod get_format;
145mod pixel;
146mod texture_import;
147mod ty_support;
148
149
150mod textures {
151 #![allow(clippy::all)]
152 include!(concat!(env!("OUT_DIR"), "/textures.rs"));
153}
154pub use self::textures::*;
155
156#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
158#[allow(missing_docs)] pub enum CubeLayer {
160 PositiveX,
161 NegativeX,
162 PositiveY,
163 NegativeY,
164 PositiveZ,
165 NegativeZ,
166}
167
168impl CubeLayer {
169 pub fn get_layer_index(&self) -> usize {
175 match self {
176 CubeLayer::PositiveX => 0,
177 CubeLayer::NegativeX => 1,
178 CubeLayer::PositiveY => 2,
179 CubeLayer::NegativeY => 3,
180 CubeLayer::PositiveZ => 4,
181 CubeLayer::NegativeZ => 5,
182 }
183 }
184}
185
186#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
188#[allow(missing_docs)] pub enum TextureKind {
190 Float,
191 Integral,
192 Unsigned,
193 Depth,
194 Stencil,
195 DepthStencil,
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
200pub enum MipmapsOption {
201 NoMipmap,
203
204 EmptyMipmaps,
206
207 EmptyMipmapsMax(u32),
210
211 AutoGeneratedMipmaps,
216
217 AutoGeneratedMipmapsMax(u32),
223}
224
225impl MipmapsOption {
226 #[inline]
228 fn should_generate(self) -> bool {
229 use self::MipmapsOption::*;
230 matches!(self, AutoGeneratedMipmaps | AutoGeneratedMipmapsMax(_))
231 }
232
233 fn num_levels(self, width: u32, height: Option<u32>, depth: Option<u32>) -> u32 {
235 use self::MipmapsOption::*;
236 use std::cmp;
237 use std::num::FpCategory;
238
239 match self {
240 NoMipmap => 1,
241 EmptyMipmaps | AutoGeneratedMipmaps => {
242 let max_dimension = cmp::max(width, cmp::max(height.unwrap_or(1),
243 depth.unwrap_or(1))) as f32;
244
245 if max_dimension.classify() == FpCategory::Zero {
246 1
247 } else {
248 1 + max_dimension.log2() as u32
249 }
250 },
251 EmptyMipmapsMax(i) | AutoGeneratedMipmapsMax(i) => {
252 let max = EmptyMipmaps.num_levels(width, height, depth) - 1;
253 if i > max { panic!("Too many mipmap levels, received {}, maximum for this texture dimension is {}.", i, max);
255 }
256 1 + i
257 },
258 }
259 }
260}
261
262impl From<CompressedMipmapsOption> for MipmapsOption {
263 fn from(opt: CompressedMipmapsOption) -> MipmapsOption {
264 match opt {
265 CompressedMipmapsOption::NoMipmap => MipmapsOption::NoMipmap,
266 CompressedMipmapsOption::EmptyMipmaps => MipmapsOption::EmptyMipmaps,
267 CompressedMipmapsOption::EmptyMipmapsMax(i) => MipmapsOption::EmptyMipmapsMax(i),
268 }
269 }
270}
271
272#[derive(Debug, Copy, Clone, Eq, PartialEq)]
274pub enum CompressedMipmapsOption {
275 NoMipmap,
277
278 EmptyMipmaps,
280
281 EmptyMipmapsMax(u32),
284}
285
286pub trait Texture1dDataSource<'a> {
288 type Data: Send + Copy + Clone + 'a;
290
291 fn into_raw(self) -> RawImage1d<'a, Self::Data>;
293}
294
295pub trait Texture1dDataSink<T> {
302 fn from_raw(data: Cow<'_, [T]>, width: u32) -> Self where [T]: ToOwned;
304}
305
306pub struct RawImage1d<'a, T: Clone> {
308 pub data: Cow<'a, [T]>,
314
315 pub width: u32,
317
318 pub format: ClientFormat,
320}
321
322impl<'a, P: PixelValue> Texture1dDataSource<'a> for Vec<P> where P: Copy + Clone + Send + 'static {
323 type Data = P;
324
325 #[inline]
326 fn into_raw(self) -> RawImage1d<'a, P> {
327 let width = self.len() as u32;
328
329 RawImage1d {
330 data: Cow::Owned(self),
331 width,
332 format: <P as PixelValue>::get_format(),
333 }
334 }
335}
336
337impl<'a, P: PixelValue + Clone> Texture1dDataSource<'a> for RawImage1d<'a, P> {
338 type Data = P;
339
340 #[inline]
341 fn into_raw(self) -> RawImage1d<'a, P> {
342 self
343 }
344}
345
346impl<P> Texture1dDataSink<P> for Vec<P> where P: Copy + Clone + Send {
347 #[inline]
348 fn from_raw(data: Cow<'_, [P]>, _width: u32) -> Self {
349 data.into_owned()
350 }
351}
352
353impl<'a, P: PixelValue> Texture1dDataSource<'a> for &'a[P] where P: Copy + Clone + Send + 'static {
354 type Data = P;
355
356 #[inline]
357 fn into_raw(self) -> RawImage1d<'a, P> {
358 let width = self.len();
359
360 RawImage1d {
361 data: Cow::Borrowed(self),
362 width: width as u32,
363 format: <P as PixelValue>::get_format(),
364 }
365 }
366}
367
368impl<'a, T: Clone + 'a> RawImage1d<'a, T> {
369
370 pub fn from_raw_rgb(data: Vec<T>) -> RawImage1d<'a, T>
372 where T: ToClientFormat {
373 RawImage1d {
374 width: (data.len() / 3) as u32,
375 data: Cow::Owned(data),
376 format: T::rgb_format(),
377 }
378 }
379
380 pub fn from_raw_rgba(data: Vec<T>) -> RawImage1d<'a, T>
382 where T: ToClientFormat {
383 RawImage1d {
384 width: (data.len() / 4) as u32,
385 data: Cow::Owned(data),
386 format: T::rgba_format(),
387 }
388 }
389}
390
391pub trait Texture2dDataSource<'a> {
393 type Data: Send + Copy + Clone + 'a;
395
396 fn into_raw(self) -> RawImage2d<'a, Self::Data>;
398}
399
400pub trait Texture2dDataSink<T> {
407 fn from_raw(data: Cow<'_, [T]>, width: u32, height: u32) -> Self where [T]: ToOwned;
409}
410
411pub struct RawImage2d<'a, T: Clone> {
413 pub data: Cow<'a, [T]>,
420
421 pub width: u32,
423
424 pub height: u32,
426
427 pub format: ClientFormat,
429}
430
431#[allow(missing_docs)]
432pub trait ToClientFormat {
433 fn rgb_format() -> ClientFormat;
434 fn rgba_format() -> ClientFormat;
435}
436
437impl ToClientFormat for u8 {
438 fn rgb_format() -> ClientFormat { ClientFormat::U8U8U8 }
439 fn rgba_format() -> ClientFormat { ClientFormat::U8U8U8U8 }
440}
441
442impl ToClientFormat for i8 {
443 fn rgb_format() -> ClientFormat { ClientFormat::I8I8I8 }
444 fn rgba_format() -> ClientFormat { ClientFormat::I8I8I8I8 }
445}
446
447impl ToClientFormat for u16 {
448 fn rgb_format() -> ClientFormat { ClientFormat::U16U16U16 }
449 fn rgba_format() -> ClientFormat { ClientFormat::U16U16U16U16 }
450}
451
452impl ToClientFormat for i16 {
453 fn rgb_format() -> ClientFormat { ClientFormat::I16I16I16 }
454 fn rgba_format() -> ClientFormat { ClientFormat::I16I16I16I16 }
455}
456
457impl ToClientFormat for u32 {
458 fn rgb_format() -> ClientFormat { ClientFormat::U32U32U32 }
459 fn rgba_format() -> ClientFormat { ClientFormat::U32U32U32U32 }
460}
461
462impl ToClientFormat for i32 {
463 fn rgb_format() -> ClientFormat { ClientFormat::I32I32I32 }
464 fn rgba_format() -> ClientFormat { ClientFormat::I32I32I32I32 }
465}
466
467impl ToClientFormat for f32 {
468 fn rgb_format() -> ClientFormat { ClientFormat::F32F32F32 }
469 fn rgba_format() -> ClientFormat { ClientFormat::F32F32F32F32 }
470}
471
472impl<'a, T: Clone + 'a> RawImage2d<'a, T> {
473 pub fn from_raw_rgb(data: Vec<T>, dimensions: (u32, u32)) -> RawImage2d<'a, T>
477 where T: ToClientFormat {
478 RawImage2d {
479 data: Cow::Owned(data),
480 width: dimensions.0,
481 height: dimensions.1,
482 format: T::rgb_format(),
483 }
484 }
485
486 pub fn from_raw_rgba(data: Vec<T>, dimensions: (u32, u32)) -> RawImage2d<'a, T>
490 where T: ToClientFormat {
491 RawImage2d {
492 data: Cow::Owned(data),
493 width: dimensions.0,
494 height: dimensions.1,
495 format: T::rgba_format(),
496 }
497 }
498
499 pub fn from_raw_rgb_reversed(data: &[T], dimensions: (u32, u32)) -> RawImage2d<'a, T>
503 where T: ToClientFormat {
504 let data = data
505 .chunks(dimensions.0 as usize * 3)
506 .rev()
507 .flat_map(|row| row.iter()).cloned()
508 .collect();
509
510 RawImage2d::from_raw_rgb(data, dimensions)
511 }
512
513 pub fn from_raw_rgba_reversed(data: &[T], dimensions: (u32, u32)) -> RawImage2d<'a, T>
517 where T: ToClientFormat {
518 let data = data
519 .chunks(dimensions.0 as usize * 4)
520 .rev()
521 .flat_map(|row| row.iter()).cloned()
522 .collect();
523
524 RawImage2d::from_raw_rgba(data, dimensions)
525 }
526
527 pub fn from_vec_raw1d(arr: &Vec<RawImage1d<'a, T>>) -> RawImage2d<'a, T> {
529 let width = arr[0].width;
530 let height = arr.len() as u32;
531 let format = arr[0].format;
532 let raw_data = {
533 let mut vec = Vec::<T>::with_capacity((width * height) as usize);
534 for i in arr {
535 if width != i.width {
536 panic!("Varying dimensions were found.");
537 } else if format != i.format {
538 panic!("Varying formats were found.");
539 }
540 for j in i.data.iter() {
541 vec.push(j.clone());
542 }
543 }
544 vec
545 };
546 RawImage2d {
547 data: Cow::Owned(raw_data),
548 width,
549 height,
550 format,
551 }
552 }
553}
554
555impl<'a, P: PixelValue + Clone> Texture2dDataSource<'a> for Vec<Vec<P>> {
556 type Data = P;
557
558 fn into_raw(self) -> RawImage2d<'a, P> {
559 let width = self.get(0).map(|e| e.len()).unwrap_or(0) as u32;
560 let height = self.len() as u32;
561
562 RawImage2d {
563 data: Cow::Owned(self.into_iter().flat_map(|e| e.into_iter()).collect()),
564 width,
565 height,
566 format: <P as PixelValue>::get_format(),
567 }
568 }
569}
570
571impl<'a, P: PixelValue + Clone> Texture2dDataSource<'a> for RawImage2d<'a, P> {
572 type Data = P;
573
574 #[inline]
575 fn into_raw(self) -> RawImage2d<'a, P> {
576 self
577 }
578}
579
580impl<P> Texture2dDataSink<P> for Vec<Vec<P>> where P: Copy + Clone {
581 fn from_raw(data: Cow<'_, [P]>, width: u32, height: u32) -> Self {
582 data.chunks(width as usize).map(|e| e.to_vec()).collect()
583 }
584}
585
586macro_rules! impl_2d_sink_for_raw_image {
587 (($t1:ty, $t2:ty, $t3:ty, $t4:ty)) => (
588 impl<'a> Texture2dDataSink<($t1, $t2, $t3, $t4)> for RawImage2d<'a, $t1> {
589 fn from_raw(data: Cow<'_, [($t1, $t2, $t3, $t4)]>, width: u32, height: u32) -> Self {
590 RawImage2d {
591 data: Cow::Owned( {
592 let mut v = Vec::with_capacity(data.len() * 4);
593 for (a, b, c, d) in data.into_owned() {
594 v.push(a);
595 v.push(b);
596 v.push(c);
597 v.push(d);
598 }
599 v
600 } ),
601 width,
602 height,
603 format: <($t1, $t2, $t3, $t4) as PixelValue>::get_format(),
604 }
605 }
606 }
607 );
608 (($t1:ty, $t2:ty, $t3:ty)) => (
609 impl<'a> Texture2dDataSink<($t1, $t2, $t3)> for RawImage2d<'a, $t1> {
610 fn from_raw(data: Cow<'_, [($t1, $t2, $t3)]>, width: u32, height: u32) -> Self {
611 RawImage2d {
612 data: Cow::Owned( {
613 let mut v = Vec::with_capacity(data.len() * 3);
614 for (a, b, c) in data.into_owned() {
615 v.push(a);
616 v.push(b);
617 v.push(c);
618 }
619 v
620 } ),
621 width,
622 height,
623 format: <($t1, $t2, $t3) as PixelValue>::get_format(),
624 }
625 }
626 }
627 );
628 (($t1:ty, $t2:ty)) => (
629 impl<'a> Texture2dDataSink<($t1, $t2)> for RawImage2d<'a, $t1> {
630 fn from_raw(data: Cow<'_, [($t1, $t2)]>, width: u32, height: u32) -> Self {
631 RawImage2d {
632 data: Cow::Owned( {
633 let mut v = Vec::with_capacity(data.len() * 2);
634 for (a, b) in data.into_owned() {
635 v.push(a);
636 v.push(b);
637 }
638 v
639 } ),
640 width,
641 height,
642 format: <($t1, $t2) as PixelValue>::get_format(),
643 }
644 }
645 }
646 );
647 ($t1:ty) => (
648 impl<'a> Texture2dDataSink<$t1> for RawImage2d<'a, $t1> {
649 fn from_raw(data: Cow<'_, [$t1]>, width: u32, height: u32) -> Self {
650 RawImage2d {
651 data: Cow::Owned(data.into_owned()),
652 width,
653 height,
654 format: <$t1 as PixelValue>::get_format(),
655 }
656 }
657 }
658 );
659}
660
661impl_2d_sink_for_raw_image!(i8);
662impl_2d_sink_for_raw_image!((i8, i8));
663impl_2d_sink_for_raw_image!((i8, i8, i8));
664impl_2d_sink_for_raw_image!((i8, i8, i8, i8));
665impl_2d_sink_for_raw_image!(u8);
666impl_2d_sink_for_raw_image!((u8, u8));
667impl_2d_sink_for_raw_image!((u8, u8, u8));
668impl_2d_sink_for_raw_image!((u8, u8, u8, u8));
669impl_2d_sink_for_raw_image!(i16);
670impl_2d_sink_for_raw_image!((i16, i16));
671impl_2d_sink_for_raw_image!((i16, i16, i16));
672impl_2d_sink_for_raw_image!((i16, i16, i16, i16));
673impl_2d_sink_for_raw_image!(u16);
674impl_2d_sink_for_raw_image!((u16, u16));
675impl_2d_sink_for_raw_image!((u16, u16, u16));
676impl_2d_sink_for_raw_image!((u16, u16, u16, u16));
677impl_2d_sink_for_raw_image!(i32);
678impl_2d_sink_for_raw_image!((i32, i32));
679impl_2d_sink_for_raw_image!((i32, i32, i32));
680impl_2d_sink_for_raw_image!((i32, i32, i32, i32));
681impl_2d_sink_for_raw_image!(u32);
682impl_2d_sink_for_raw_image!((u32, u32));
683impl_2d_sink_for_raw_image!((u32, u32, u32));
684impl_2d_sink_for_raw_image!((u32, u32, u32, u32));
685impl_2d_sink_for_raw_image!(f32);
686impl_2d_sink_for_raw_image!((f32, f32));
687impl_2d_sink_for_raw_image!((f32, f32, f32));
688impl_2d_sink_for_raw_image!((f32, f32, f32, f32));
689
690pub trait Texture3dDataSource<'a> {
692 type Data: Send + Copy + Clone + 'a;
694
695 fn into_raw(self) -> RawImage3d<'a, Self::Data>;
697}
698
699pub trait Texture3dDataSink<T> {
706 fn from_raw(data: Cow<'_, [T]>, width: u32, height: u32, depth: u32) -> Self where [T]: ToOwned;
708}
709
710pub struct RawImage3d<'a, T: Clone> {
712 pub data: Cow<'a, [T]>,
716
717 pub width: u32,
719
720 pub height: u32,
722
723 pub depth: u32,
725
726 pub format: ClientFormat,
728}
729
730impl<'a, T: Clone + 'a> RawImage3d<'a, T> {
731 pub fn from_vec_raw2d(arr: &Vec<RawImage2d<'a, T>>) -> RawImage3d<'a, T> {
733 let depth = arr.len() as u32;
734 let width = arr[0].width;
735 let height = arr[0].height;
736 let format = arr[0].format;
737 let raw_data = {
738 let mut vec = Vec::<T>::with_capacity((width * height * depth) as usize);
739 for i in arr {
740 if width != i.width || height != i.height {
741 panic!("Varying dimensions were found.");
742 } else if format != i.format {
743 panic!("Varying formats were found.");
744 }
745 for j in i.data.iter() {
746 vec.push(j.clone());
747 }
748 }
749 vec
750 };
751 RawImage3d {
752 data: Cow::Owned(raw_data),
753 width,
754 height,
755 depth,
756 format,
757 }
758 }
759}
760
761impl<'a, P: PixelValue + Clone> Texture3dDataSource<'a> for Vec<Vec<Vec<P>>> {
762 type Data = P;
763
764 fn into_raw(self) -> RawImage3d<'a, P> {
765 let width = self.get(0).and_then(|e| e.iter().next()).map(|e| e.len()).unwrap_or(0)
766 as u32;
767 let height = self.get(0).map(|e| e.len()).unwrap_or(0) as u32;
768 let depth = self.len() as u32;
769
770 RawImage3d {
771 data: self.into_iter().flat_map(|e| e.into_iter()).flat_map(|e| e.into_iter())
772 .collect(),
773 width,
774 height,
775 depth,
776 format: <P as PixelValue>::get_format(),
777 }
778 }
779}
780
781impl<'a, P: PixelValue + Clone> Texture3dDataSource<'a> for RawImage3d<'a, P> {
782 type Data = P;
783
784 #[inline]
785 fn into_raw(self) -> RawImage3d<'a, P> {
786 self
787 }
788}
789
790impl<P> Texture3dDataSink<P> for Vec<Vec<Vec<P>>> where P: Copy + Clone {
791 #[inline]
792 fn from_raw(_data: Cow<'_, [P]>, _width: u32, _height: u32, _depth: u32) -> Self {
793 unimplemented!()
794 }
795}
796
797#[derive(Debug, Clone, Copy, PartialEq, Eq)]
799pub enum TextureCreationError {
800 FormatNotSupported,
802
803 DimensionsNotSupported,
805
806 TypeNotSupported,
808
809 DataSizeMismatch,
811}
812
813impl fmt::Display for TextureCreationError {
814 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
815 use self::TextureCreationError::*;
816 let desc = match *self {
817 FormatNotSupported =>
818 "The requested format is not supported by the backend",
819 DimensionsNotSupported =>
820 "The requested texture dimensions are not supported",
821 TypeNotSupported =>
822 "The texture format is not supported by the backend",
823 DataSizeMismatch =>
824 "The size of the data doesn't match the texture dimensions",
825 };
826 fmt.write_str(desc)
827 }
828}
829
830impl Error for TextureCreationError {}
831
832impl From<FormatNotSupportedError> for TextureCreationError {
833 #[inline]
834 fn from(_: FormatNotSupportedError) -> TextureCreationError {
835 TextureCreationError::FormatNotSupported
836 }
837}