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