Skip to main content

three_d_asset/
texture.rs

1//!
2//! Contain texture asset definitions.
3//!
4
5pub(crate) mod texture2d;
6pub use texture2d::*;
7
8pub(crate) mod texture3d;
9pub use texture3d::*;
10
11pub use crate::prelude::f16;
12use crate::Srgba;
13
14///
15/// Possible modes of interpolation which determines the texture output between texture pixels.
16///
17#[allow(missing_docs)]
18#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub enum Interpolation {
21    Nearest,
22    #[default]
23    Linear,
24    CubicSpline,
25}
26
27/// Mipmap settings for a texture.
28#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub struct Mipmap {
31    /// Specifies what type of interpolation to use between the two closest mipmaps.
32    pub filter: Interpolation,
33    /// Specifies the maximum number of mipmap levels that should be created for the texture.
34    /// If this is 1, no mip maps will be created.
35    pub max_levels: u32,
36    /// Specifies the maximum ratio of anisotropy to be used when creating mipmaps for the texture.
37    /// If this is 1, only isotropic mipmaps will be created.
38    pub max_ratio: u32,
39}
40
41impl Default for Mipmap {
42    fn default() -> Self {
43        Self {
44            filter: Interpolation::Linear,
45            max_levels: u32::MAX,
46            max_ratio: 1,
47        }
48    }
49}
50
51///
52/// Possible wrapping modes for a texture which determines how the texture is applied outside of the
53/// [0..1] uv coordinate range.
54///
55#[allow(missing_docs)]
56#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58pub enum Wrapping {
59    Repeat,
60    MirroredRepeat,
61    ClampToEdge,
62}
63
64///
65/// The pixel/texel data for a [Texture2D] or [Texture3D].
66///
67/// If 2D data, the data array should start with the top left texel and then one row at a time.
68/// The indices `(row, column)` into the 2D data would look like
69/// ```notrust
70/// [
71/// (0, 0), (1, 0), .., // First row
72/// (0, 1), (1, 1), .., // Second row
73/// ..
74/// ]
75/// ```
76/// If 3D data, the data array would look like the 2D data, one layer/image at a time.
77/// The indices `(row, column, layer)` into the 3D data would look like
78/// ```notrust
79/// [
80/// (0, 0, 0), (1, 0, 0), .., // First row in first layer
81/// (0, 1, 0), (1, 1, 0), .., // Second row in first layer
82/// ..
83/// (0, 0, 1), (1, 0, 1), .., // First row in second layer
84/// (0, 1, 1), (1, 1, 1), ..,  // Second row in second layer
85/// ..
86/// ]
87/// ```
88///
89#[derive(Clone, PartialEq)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91pub enum TextureData {
92    /// One byte in the red channel.
93    RU8(Vec<u8>),
94    /// One byte in the red and green channel.
95    RgU8(Vec<[u8; 2]>),
96    /// One byte in the red, green and blue channel.
97    RgbU8(Vec<[u8; 3]>),
98    /// One byte in the red, green, blue and alpha channel.
99    RgbaU8(Vec<[u8; 4]>),
100
101    /// 16-bit float in the red channel.
102    RF16(Vec<f16>),
103    /// 16-bit float in the red and green channel.
104    RgF16(Vec<[f16; 2]>),
105    /// 16-bit float in the red, green and blue channel.
106    RgbF16(Vec<[f16; 3]>),
107    /// 16-bit float in the red, green, blue and alpha channel.
108    RgbaF16(Vec<[f16; 4]>),
109
110    /// 32-bit float in the red channel.
111    RF32(Vec<f32>),
112    /// 32-bit float in the red and green channel.
113    RgF32(Vec<[f32; 2]>),
114    /// 32-bit float in the red, green and blue channel.
115    RgbF32(Vec<[f32; 3]>),
116    /// 32-bit float in the red, green, blue and alpha channel.
117    RgbaF32(Vec<[f32; 4]>),
118}
119
120impl std::fmt::Debug for TextureData {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        match self {
123            Self::RU8(values) => write!(f, "R u8 ({:?})", values.len()),
124            Self::RgU8(values) => write!(f, "RG u8 ({:?})", values.len()),
125            Self::RgbU8(values) => write!(f, "RGB u8 ({:?})", values.len()),
126            Self::RgbaU8(values) => write!(f, "RGBA u8 ({:?})", values.len()),
127            Self::RF16(values) => write!(f, "R f16 ({:?})", values.len()),
128            Self::RgF16(values) => write!(f, "RG f16 ({:?})", values.len()),
129            Self::RgbF16(values) => write!(f, "RGB f16 ({:?})", values.len()),
130            Self::RgbaF16(values) => write!(f, "RGBA f16 ({:?})", values.len()),
131            Self::RF32(values) => write!(f, "R f32 ({:?})", values.len()),
132            Self::RgF32(values) => write!(f, "RG f32 ({:?})", values.len()),
133            Self::RgbF32(values) => write!(f, "RGB f32 ({:?})", values.len()),
134            Self::RgbaF32(values) => write!(f, "RGBA f32 ({:?})", values.len()),
135        }
136    }
137}
138
139impl TextureData {
140    ///
141    /// Converts the texture data to linear sRGB color space if the data is either
142    /// [TextureData::RgbU8] (assuming sRGB color space) or [TextureData::RgbaU8] (assuming sRGB color space with an alpha channel).
143    /// Does nothing if the data is any other data type.
144    ///
145    pub fn to_linear_srgb(&mut self) {
146        match self {
147            TextureData::RgbU8(data) => data.iter_mut().for_each(|color| {
148                *color = Srgba::from(Srgba::from(*color).to_linear_srgb()).into();
149            }),
150            TextureData::RgbaU8(data) => data.iter_mut().for_each(|color| {
151                *color = Srgba::from(Srgba::from(*color).to_linear_srgb()).into();
152            }),
153            _ => {}
154        };
155    }
156
157    ///
158    /// Converts the texture data to color [TextureData::RgbU8] if the data is [TextureData::RU8] (assuming gray scale colors).
159    /// Does nothing if the data is any other data type.
160    ///
161    pub fn to_color(&mut self) {
162        if let TextureData::RU8(data) = self {
163            *self = TextureData::RgbU8(data.iter().map(|color| [*color, *color, *color]).collect())
164        };
165    }
166}