glium/texture/
mod.rs

1/*!
2A texture is an image loaded in video memory, which can be sampled in your shaders.
3
4# Texture kinds
5
6One thing that is important to understand when it comes to textures is that the way a texture is
7accessed (in other words, its "public API") is disconnected from the internal representation
8of the data.
9
10When it comes to accessing a texture, there are six kinds of textures:
11
12 - Floating-point textures.
13 - Integral textures (that contain signed integers).
14 - Unsigned textures (that contain unsigned integers).
15 - Depth textures (that contain depth information).
16 - Stencil textures (that contain stencil information).
17 - Depth-stencil textures (that contain at the same time depth and stencil information).
18
19Textures have a different API depending on their kind. For example a integral texture can only
20be sampled in GLSL through a sampler type which is prefixed with `i`.
21
22The internal format can only be chosen when the texture is created, and then can never be touched
23again. Integral and unsigned textures can only contain signed integers and unsigned integers.
24
25Floating-point textures can contain either floating-points or integers. If integers are used,
26then the maximum value corresponds to the floating-point value `1.0` and the minimal value to `0.0`.
27For example if a texture contains `u8`s and internally contains the value `128`, reading from the
28texture will yield the value `0.5`.
29
30# Dimensions
31
32Textures come in nine different dimensions:
33
34 - Textures with one dimension.
35 - Textures with two dimensions.
36 - Textures with two dimensions and multisampling enabled.
37 - Textures with three dimensions.
38 - Cube textures, which are arrays of six two-dimensional textures
39   corresponding to the six faces of a cube.
40 - Arrays of one-dimensional textures.
41 - Arrays of two-dimensional textures.
42 - Arrays of two-dimensional textures with multisampling enabled.
43 - Arrays of cube textures.
44
45The difference between a 3D texture and a 2D textures array (and between a 2D texture and a 1D
46textures array) is that texture arrays can only be accessed by individual layers. That is, you can
47only access layer 0, or layer 1, or layer 2, and so on. Whereas if you use 3D textures you can
48access layer `0.5` for example.
49
50All textures except depth, stencil and depth-stencil textures have **mipmaps**. A mipmap is a
51smaller version of the texture whose purpose is to be used during rendering when the texture will
52be small on the screen.
53
54# Texture types in glium
55
56In addition to the nine different dimensions types, there are nine kinds of texture formats:
57
58 - The texture contains floating-point data,
59   with either the `Compressed` prefix or no prefix at all.
60 - The texture contains floating-point data in the sRGB color space, with either the `Compressed`
61   prefix or not.
62 - The texture contains signed integers, with the `Integral` prefix.
63 - The texture contains unsigned integers, with the `Unsigned` prefix.
64 - The texture contains depth information, with the `Depth` prefix.
65 - The texture contains stencil information, with the `Stencil` prefix.
66 - The texture contains depth and stencil information, with the `DepthStencil` prefix.
67
68Each combination of dimensions and format corresponds to a sampler type in GLSL and in glium.
69For example, an `IntegralTexture3d` can only be bound to an `isampler3D` uniform in GLSL.
70
71The difference between compressed textures and uncompressed textures is that you can't do
72render-to-texture on the former.
73
74The most common types of textures are `CompressedSrgbTexture2d`, `SrgbTexture2d` and `Texture2d`
75(the two dimensions being the width and height). These are what you will use most of the time.
76
77# Buffer textures
78
79A `BufferTexture` is a special kind of one-dimensional texture that gets its data from a buffer.
80Buffer textures have very limited capabilities (you can't draw to them for example). They are an
81alternative to uniform buffers and SSBOs.
82
83See the `buffer_textures` module for more infos.
84
85# About sRGB
86
87For historical reasons, the color data contained in almost all image files are not in RGB but
88in sRGB. sRGB colors are slightly brighter than linear RGB in order to compensate for the fact
89that screens darken some values that they receive.
90
91When you load image files, you are encouraged to create sRGB textures (with `SrgbTexture2d` instead
92of `Texture2d` for example).
93
94By default, glium enables the `GL_FRAMEBUFFER_SRGB` trigger, which expects the output of your
95fragment shader to be in linear RGB and then turns it into sRGB before writing in the framebuffer.
96Sampling from an sRGB texture will convert the texture colors from sRGB to RGB. If you create a
97regular RGB texture and put sRGB data in it, then the result will be too bright.
98
99# Bindless textures
100
101*Bindless textures are a very recent feature that is supported only by recent hardware and
102drivers.*
103
104Without bindless textures, using a texture in a shader requires binding the texture to a specific
105bind point before drawing. This not only slows down rendering, but may also prevent you from
106grouping multiple draw calls into one because of the limitation to the number of available
107texture units.
108
109Instead, bindless textures allow you to manually manipulate pointers to textures in video memory.
110You can use thousands of textures if you want.
111
112*/
113#![allow(unreachable_code)]     // TODO: remove
114
115use 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/// Represents a layer of a cubemap.
157#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
158#[allow(missing_docs)]      // TODO:
159pub enum CubeLayer {
160    PositiveX,
161    NegativeX,
162    PositiveY,
163    NegativeY,
164    PositiveZ,
165    NegativeZ,
166}
167
168impl CubeLayer {
169    /// In some situations whole cubemaps can be bound at once. If this is the case, each layer
170    /// of the cubemap has a specific index.
171    ///
172    /// For example, if you bind a whole cubemap array, then the index `8` will correspond to the
173    /// `PositiveY` face of the cubemap whose index is `1` in the array.
174    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/// Represents a kind of texture.
187#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
188#[allow(missing_docs)]      // TODO:
189pub enum TextureKind {
190    Float,
191    Integral,
192    Unsigned,
193    Depth,
194    Stencil,
195    DepthStencil,
196}
197
198/// Describes what to do about mipmaps during texture creation.
199#[derive(Debug, Copy, Clone, Eq, PartialEq)]
200pub enum MipmapsOption {
201    /// No mipmap will be allocated or generated.
202    NoMipmap,
203
204    /// Allocates space for all the possible amount of mipmaps given the texture dimensions.
205    EmptyMipmaps,
206
207    /// Allocates space for the specified amount of mipmaps (excluding the top level) but does not
208    /// generate mipmaps.
209    EmptyMipmapsMax(u32),
210
211    /// Allocates and generates mipmaps for all the possible levels given the texture dimensions.
212    ///
213    /// This does not mean that you will get mipmaps, instead it indicates that mipmaps are *allowed*
214    /// to be generated if possible.
215    AutoGeneratedMipmaps,
216
217    /// Allocates and generates mipmaps for the specified amount of mipmaps (excluding the top level)
218    /// the possible levels given the texture dimensions.
219    ///
220    /// This does not mean that you will get mipmaps, instead it indicates that mipmaps are *allowed*
221    /// to be generated if possible.
222    AutoGeneratedMipmapsMax(u32),
223}
224
225impl MipmapsOption {
226    /// Tells whether mipmaps should be automatically generated.
227    #[inline]
228    fn should_generate(self) -> bool {
229        use self::MipmapsOption::*;
230        matches!(self, AutoGeneratedMipmaps | AutoGeneratedMipmapsMax(_))
231    }
232
233    /// Number of levels (including the main level).
234    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 { // TODO should we perform this check or just clamp the value?
254                    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/// Describes what to do about mipmaps during compressed texture creation.
273#[derive(Debug, Copy, Clone, Eq, PartialEq)]
274pub enum CompressedMipmapsOption {
275    /// No mipmaps will be allocated or generated.
276    NoMipmap,
277
278    /// Allocates space for all the possible amount of mipmaps given the texture dimensions.
279    EmptyMipmaps,
280
281    /// Allocates space for the specified amount of mipmaps (excluding the top level) but does not
282    /// generate mipmaps.
283    EmptyMipmapsMax(u32),
284}
285
286/// Trait that describes data for a one-dimensional texture.
287pub trait Texture1dDataSource<'a> {
288    /// The type of each pixel.
289    type Data: Send + Copy + Clone + 'a;
290
291    /// Returns the raw representation of the data.
292    fn into_raw(self) -> RawImage1d<'a, Self::Data>;
293}
294
295/// Trait that describes types that can be built from one-dimensional texture data.
296///
297/// The parameter indicates the type of pixels accepted by this sink.
298///
299/// You are especially encouraged to implement this trait with the parameter `(u8, u8, u8, u8)`,
300/// as this is the only format that is guaranteed to be supported by OpenGL when reading pixels.
301pub trait Texture1dDataSink<T> {
302    /// Builds a new object from raw data.
303    fn from_raw(data: Cow<'_, [T]>, width: u32) -> Self where [T]: ToOwned;
304}
305
306/// Represents raw data for a two-dimensional image.
307pub struct RawImage1d<'a, T: Clone> {
308    /// A contiguous array of pixel data.
309    ///
310    /// The data must start by the left pixel and progress left-to-right.
311    ///
312    /// `data.len()` must be equal to `width * format.get_size() / mem::size_of::<T>()`.
313    pub data: Cow<'a, [T]>,
314
315    /// Number of pixels per column.
316    pub width: u32,
317
318    /// Formats of the pixels.
319    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    /// Builds a raw 1d image from a vector of interleaved RGB values.
371    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    /// Builds a raw 1d image from a vector of interleaved RGBA values.
381    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
391/// Trait that describes data for a two-dimensional texture.
392pub trait Texture2dDataSource<'a> {
393    /// The type of each pixel.
394    type Data: Send + Copy + Clone + 'a;
395
396    /// Returns the raw representation of the data.
397    fn into_raw(self) -> RawImage2d<'a, Self::Data>;
398}
399
400/// Trait that describes types that can be built from two-dimensional texture data.
401///
402/// The parameter indicates the type of pixels accepted by this sink.
403///
404/// You are especially encouraged to implement this trait with the parameter `(u8, u8, u8, u8)`,
405/// as this is the only format that is guaranteed to be supported by OpenGL when reading pixels.
406pub trait Texture2dDataSink<T> {
407    /// Builds a new object from raw data.
408    fn from_raw(data: Cow<'_, [T]>, width: u32, height: u32) -> Self where [T]: ToOwned;
409}
410
411/// Represents raw data for a two-dimensional image.
412pub struct RawImage2d<'a, T: Clone> {
413    /// A contiguous array of pixel data.
414    ///
415    /// The data must start by the bottom-left hand corner pixel and progress left-to-right and
416    /// bottom-to-top.
417    ///
418    /// `data.len()` must be equal to `width * height * format.get_size() / mem::size_of::<T>()`.
419    pub data: Cow<'a, [T]>,
420
421    /// Number of pixels per column.
422    pub width: u32,
423
424    /// Number of pixels per row.
425    pub height: u32,
426
427    /// Formats of the pixels.
428    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    /// Builds a raw image from a vector of interleaved RGB values.
474    ///
475    /// The first pixel is at (0, 0), the last pixel is at (1, 1).
476    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    /// Builds a raw image from a vector of interleaved RGBA values.
487    ///
488    /// The first pixel is at (0, 0), the last pixel is at (1, 1).
489    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    /// Builds a raw image from a vector of interleaved RGB values, flipping it vertically.
500    ///
501    /// The first pixel is at (0, 1), the last pixel is at (1, 0).
502    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    /// Builds a raw image from a vector of interleaved RGBA values, flipping it vertically.
514    ///
515    /// The first pixel is at (0, 1), the last pixel is at (1, 0).
516    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    /// Transforms a `Vec<RawImage1d>` into a `RawImage2d`
528    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
690/// Trait that describes data for a two-dimensional texture.
691pub trait Texture3dDataSource<'a> {
692    /// The type of each pixel.
693    type Data: Send + Copy + Clone + 'a;
694
695    /// Returns the raw representation of the data.
696    fn into_raw(self) -> RawImage3d<'a, Self::Data>;
697}
698
699/// Trait that describes types that can be built from one-dimensional texture data.
700///
701/// The parameter indicates the type of pixels accepted by this sink.
702///
703/// You are especially encouraged to implement this trait with the parameter `(u8, u8, u8, u8)`,
704/// as this is the only format that is guaranteed to be supported by OpenGL when reading pixels.
705pub trait Texture3dDataSink<T> {
706    /// Builds a new object from raw data.
707    fn from_raw(data: Cow<'_, [T]>, width: u32, height: u32, depth: u32) -> Self where [T]: ToOwned;
708}
709
710/// Represents raw data for a two-dimensional image.
711pub struct RawImage3d<'a, T: Clone> {
712    /// A contiguous array of pixel data.
713    ///
714    /// `data.len()` must be equal to `width * height * depth * format.get_size() / mem::size_of::<T>()`.
715    pub data: Cow<'a, [T]>,
716
717    /// Number of pixels per column.
718    pub width: u32,
719
720    /// Number of pixels per row.
721    pub height: u32,
722
723    /// Number of pixels per depth.
724    pub depth: u32,
725
726    /// Formats of the pixels.
727    pub format: ClientFormat,
728}
729
730impl<'a, T: Clone + 'a> RawImage3d<'a, T> {
731    /// Transforms a `Vec<RawImage2d>` into a `RawImage3d`
732    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/// Error that can happen when creating a texture.
798#[derive(Debug, Clone, Copy, PartialEq, Eq)]
799pub enum TextureCreationError {
800    /// The requested format is not supported by the backend.
801    FormatNotSupported,
802
803    /// The requested texture dimensions are not supported.
804    DimensionsNotSupported,
805
806    /// The texture format is not supported by the backend.
807    TypeNotSupported,
808
809    /// The size of the data doesn't match the texture dimensions.
810    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}