[go: up one dir, main page]

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