Skip to main content

gltf/
texture.rs

1use crate::{image, Document};
2
3pub use json::texture::{MagFilter, MinFilter, WrappingMode};
4#[cfg(feature = "extensions")]
5use serde_json::{Map, Value};
6
7/// A reference to a `Texture`.
8#[derive(Clone, Debug)]
9pub struct Info<'a> {
10    /// The parent `Texture` struct.
11    texture: Texture<'a>,
12
13    /// The corresponding JSON struct.
14    json: &'a json::texture::Info,
15}
16
17///  Texture sampler properties for filtering and wrapping modes.
18#[derive(Clone, Debug)]
19pub struct Sampler<'a> {
20    /// The parent `Document` struct.
21    #[allow(dead_code)]
22    document: &'a Document,
23
24    /// The corresponding JSON index - `None` when the default sampler.
25    index: Option<usize>,
26
27    /// The corresponding JSON struct.
28    json: &'a json::texture::Sampler,
29}
30
31/// A texture and its sampler.
32#[derive(Clone, Debug)]
33pub struct Texture<'a> {
34    /// The parent `Document` struct.
35    document: &'a Document,
36
37    /// The corresponding JSON index.
38    index: usize,
39
40    /// The corresponding JSON struct.
41    json: &'a json::texture::Texture,
42}
43
44impl<'a> Sampler<'a> {
45    /// Constructs a `Sampler`.
46    pub(crate) fn new(
47        document: &'a Document,
48        index: usize,
49        json: &'a json::texture::Sampler,
50    ) -> Self {
51        Self {
52            document,
53            index: Some(index),
54            json,
55        }
56    }
57
58    /// Constructs the default `Sampler`.
59    pub(crate) fn default(document: &'a Document) -> Self {
60        Self {
61            document,
62            index: None,
63            json: &json::texture::Sampler::DEFAULT_SAMPLER,
64        }
65    }
66
67    /// Returns the internal JSON index if this `Sampler` was explicity defined.
68    ///
69    /// This function returns `None` if the `Sampler` is the default sampler.
70    pub fn index(&self) -> Option<usize> {
71        self.index
72    }
73
74    /// Magnification filter.
75    pub fn mag_filter(&self) -> Option<MagFilter> {
76        self.json.mag_filter.map(|filter| filter.unwrap())
77    }
78
79    /// Minification filter.
80    pub fn min_filter(&self) -> Option<MinFilter> {
81        self.json.min_filter.map(|filter| filter.unwrap())
82    }
83
84    /// Optional user-defined name for this object.
85    #[cfg(feature = "names")]
86    pub fn name(&self) -> Option<&str> {
87        self.json.name.as_deref()
88    }
89
90    /// `s` wrapping mode.
91    pub fn wrap_s(&self) -> WrappingMode {
92        self.json.wrap_s.unwrap()
93    }
94
95    /// `t` wrapping mode.
96    pub fn wrap_t(&self) -> WrappingMode {
97        self.json.wrap_t.unwrap()
98    }
99
100    /// Returns extension data unknown to this crate version.
101    #[cfg(feature = "extensions")]
102    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
103    pub fn extensions(&self) -> Option<&Map<String, Value>> {
104        let ext = self.json.extensions.as_ref()?;
105        Some(&ext.others)
106    }
107
108    /// Queries extension data unknown to this crate version.
109    #[cfg(feature = "extensions")]
110    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
111    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
112        let ext = self.json.extensions.as_ref()?;
113        ext.others.get(ext_name)
114    }
115
116    /// Optional application specific data.
117    pub fn extras(&self) -> &json::Extras {
118        &self.json.extras
119    }
120}
121
122impl<'a> Texture<'a> {
123    /// Constructs a `Texture`.
124    pub(crate) fn new(
125        document: &'a Document,
126        index: usize,
127        json: &'a json::texture::Texture,
128    ) -> Self {
129        Self {
130            document,
131            index,
132            json,
133        }
134    }
135
136    /// Returns the internal JSON index.
137    pub fn index(&self) -> usize {
138        self.index
139    }
140
141    /// Optional user-defined name for this object.
142    #[cfg(feature = "names")]
143    pub fn name(&self) -> Option<&str> {
144        self.json.name.as_deref()
145    }
146
147    /// Returns the sampler used by this texture.
148    pub fn sampler(&self) -> Sampler<'a> {
149        self.json
150            .sampler
151            .as_ref()
152            .map(|index| self.document.samplers().nth(index.value()).unwrap())
153            .unwrap_or_else(|| Sampler::default(self.document))
154    }
155
156    /// Returns the image used by this texture.
157    #[cfg(feature = "allow_empty_texture")]
158    pub fn source(&self) -> Option<image::Image<'a>> {
159        let index = self.json.primary_source().value();
160        if index == u32::MAX as usize {
161            None
162        } else {
163            Some(self.document.images().nth(index).unwrap())
164        }
165    }
166
167    /// Returns the image used by this texture.
168    #[cfg(not(feature = "allow_empty_texture"))]
169    pub fn source(&self) -> image::Image<'a> {
170        self.document
171            .images()
172            .nth(self.json.primary_source().value())
173            .unwrap()
174    }
175
176    /// Returns extension data unknown to this crate version.
177    #[cfg(feature = "extensions")]
178    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
179    pub fn extensions(&self) -> Option<&Map<String, Value>> {
180        let ext = self.json.extensions.as_ref()?;
181        Some(&ext.others)
182    }
183
184    /// Queries extension data unknown to this crate version.
185    #[cfg(feature = "extensions")]
186    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
187    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
188        let ext = self.json.extensions.as_ref()?;
189        ext.others.get(ext_name)
190    }
191
192    /// Optional application specific data.
193    pub fn extras(&self) -> &json::Extras {
194        &self.json.extras
195    }
196}
197
198impl<'a> Info<'a> {
199    /// Constructs a reference to a `Texture`.
200    pub(crate) fn new(texture: Texture<'a>, json: &'a json::texture::Info) -> Self {
201        Self { texture, json }
202    }
203
204    /// The set index of the texture's `TEXCOORD` attribute.
205    pub fn tex_coord(&self) -> u32 {
206        self.json.tex_coord
207    }
208
209    /// Returns the referenced `Texture`.
210    pub fn texture(&self) -> Texture<'a> {
211        self.texture.clone()
212    }
213
214    /// Returns texture transform information
215    #[cfg(feature = "KHR_texture_transform")]
216    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_texture_transform")))]
217    pub fn texture_transform(&self) -> Option<TextureTransform<'a>> {
218        self.json
219            .extensions
220            .as_ref()?
221            .texture_transform
222            .as_ref()
223            .map(TextureTransform::new)
224    }
225
226    /// Returns extension data unknown to this crate version.
227    #[cfg(feature = "extensions")]
228    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
229    pub fn extensions(&self) -> Option<&Map<String, Value>> {
230        let ext = self.json.extensions.as_ref()?;
231        Some(&ext.others)
232    }
233
234    /// Queries extension data unknown to this crate version.
235    #[cfg(feature = "extensions")]
236    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
237    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
238        let ext = self.json.extensions.as_ref()?;
239        ext.others.get(ext_name)
240    }
241
242    /// Optional application specific data.
243    pub fn extras(&self) -> &json::Extras {
244        &self.json.extras
245    }
246}
247
248impl<'a> AsRef<Texture<'a>> for Info<'a> {
249    fn as_ref(&self) -> &Texture<'a> {
250        &self.texture
251    }
252}
253
254/// Many techniques can be used to optimize resource usage for a 3d scene.
255/// Chief among them is the ability to minimize the number of textures the GPU must load.
256/// To achieve this, many engines encourage packing many objects' low-resolution textures into a single large texture atlas.
257/// The region of the resulting atlas that corresponds with each object is then defined by vertical and horizontal offsets,
258/// and the width and height of the region.
259///
260/// To support this use case, this extension adds `offset`, `rotation`, and `scale` properties to textureInfo structures.
261/// These properties would typically be implemented as an affine transform on the UV coordinates.
262#[cfg(feature = "KHR_texture_transform")]
263pub struct TextureTransform<'a> {
264    /// The corresponding JSON struct.
265    json: &'a json::extensions::texture::TextureTransform,
266}
267
268#[cfg(feature = "KHR_texture_transform")]
269impl<'a> TextureTransform<'a> {
270    /// Constructs `TextureTransform`
271    pub(crate) fn new(json: &'a json::extensions::texture::TextureTransform) -> Self {
272        Self { json }
273    }
274
275    /// The offset of the UV coordinate origin as a factor of the texture dimensions.
276    pub fn offset(&self) -> [f32; 2] {
277        self.json.offset.0
278    }
279
280    /// Rotate the UVs by this many radians counter-clockwise around the origin.
281    /// This is equivalent to a similar rotation of the image clockwise.
282    pub fn rotation(&self) -> f32 {
283        self.json.rotation.0
284    }
285
286    /// The scale factor applied to the components of the UV coordinates.
287    pub fn scale(&self) -> [f32; 2] {
288        self.json.scale.0
289    }
290
291    /// Overrides the textureInfo texCoord value if supplied, and if this extension is supported.
292    pub fn tex_coord(&self) -> Option<u32> {
293        self.json.tex_coord
294    }
295
296    /// Optional application specific data.
297    pub fn extras(&self) -> &json::Extras {
298        &self.json.extras
299    }
300}