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}