Skip to main content

gltf/
lib.rs

1#![deny(missing_docs)]
2#![allow(unknown_lints)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5//! glTF 2.0 loader
6//!
7//! This crate is intended to load [glTF 2.0], a file format designed for the
8//! efficient runtime transmission of 3D scenes. The crate aims to provide
9//! rustic utilities that make working with glTF simple and intuitive.
10//!
11//! # Installation
12//!
13//! Add `gltf` to your `Cargo.toml`:
14//!
15//! ```toml
16//! [dependencies.gltf]
17//! version = "1"
18//! ```
19//!
20//! # Examples
21//!
22//! ## Basic usage
23//!
24//! Walking the node hierarchy.
25//!
26//! ```
27//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
28//! # use gltf::Gltf;
29//! let gltf = Gltf::open("examples/Box.gltf")?;
30//! for scene in gltf.scenes() {
31//!     for node in scene.nodes() {
32//!         println!(
33//!             "Node #{} has {} children",
34//!             node.index(),
35//!             node.children().count(),
36//!         );
37//!     }
38//! }
39//! # Ok(())
40//! # }
41//! # fn main() {
42//! #    let _ = run().expect("runtime error");
43//! # }
44//! ```
45//!
46//! ## Import function
47//!
48//! Reading a glTF document plus its buffers and images from the
49//! file system.
50//!
51//! ```
52//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
53//! let (document, buffers, images) = gltf::import("examples/Box.gltf")?;
54//! assert_eq!(buffers.len(), document.buffers().count());
55//! assert_eq!(images.len(), document.images().count());
56//! # Ok(())
57//! # }
58//! # fn main() {
59//! #    let _ = run().expect("runtime error");
60//! # }
61//! ```
62//!
63//! ### Note
64//!
65//! This function is provided as a convenience for loading glTF and associated
66//! resources from the file system. It is suitable for real world use but may
67//! not be suitable for all real world use cases. More complex import scenarios
68//! such downloading from web URLs are not handled by this function. These
69//! scenarios are delegated to the user.
70//!
71//! You can read glTF without loading resources by constructing the [`Gltf`]
72//! (standard glTF) or [`Glb`] (binary glTF) data structures explicitly. Buffer
73//! and image data can then be imported separately using [`import_buffers`] and
74//! [`import_images`] respectively.
75//!
76//! [glTF 2.0]: https://www.khronos.org/gltf
77//! [`Gltf`]: struct.Gltf.html
78//! [`Glb`]: struct.Glb.html
79//! [`Node`]: struct.Node.html
80//! [`Scene`]: struct.Scene.html
81
82#[cfg(test)]
83#[macro_use]
84extern crate approx;
85#[cfg(feature = "import")]
86extern crate image as image_crate;
87
88/// Contains (de)serializable data structures that match the glTF JSON text.
89pub extern crate gltf_json as json;
90
91/// Accessors for reading vertex attributes from buffer views.
92pub mod accessor;
93
94/// Animations, their channels, targets, and samplers.
95pub mod animation;
96
97/// Primitives for working with binary glTF.
98pub mod binary;
99
100/// Buffers and buffer views.
101pub mod buffer;
102
103/// Cameras and their projections.
104pub mod camera;
105
106/// Images that may be used by textures.
107pub mod image;
108
109/// The reference importer.
110#[cfg(feature = "import")]
111#[cfg_attr(docsrs, doc(cfg(feature = "import")))]
112mod import;
113
114/// Iterators for walking the glTF node hierarchy.
115pub mod iter;
116
117/// Support for the `KHR_lights_punctual` extension.
118#[cfg(feature = "KHR_lights_punctual")]
119#[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
120pub mod khr_lights_punctual;
121
122/// Support for the `KHR_materials_variants` extension.
123#[cfg(feature = "KHR_materials_variants")]
124#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_variants")))]
125pub mod khr_materials_variants;
126
127/// Material properties of primitives.
128pub mod material;
129
130/// For internal use.
131mod math;
132
133/// Meshes and their primitives.
134pub mod mesh;
135
136/// The glTF node heirarchy.
137pub mod scene;
138
139/// Mesh skinning primitives.
140pub mod skin;
141
142/// Textures and their samplers.
143pub mod texture;
144
145#[cfg(feature = "extensions")]
146use json::Value;
147#[cfg(feature = "extensions")]
148use serde_json::Map;
149
150#[doc(inline)]
151pub use self::accessor::Accessor;
152#[doc(inline)]
153pub use self::animation::Animation;
154#[doc(inline)]
155pub use self::binary::Glb;
156#[doc(inline)]
157pub use self::buffer::Buffer;
158#[doc(inline)]
159pub use self::camera::Camera;
160#[doc(inline)]
161pub use self::image::Image;
162#[cfg(feature = "import")]
163#[doc(inline)]
164pub use self::import::import;
165#[cfg(feature = "import")]
166#[doc(inline)]
167pub use self::import::import_buffers;
168#[cfg(feature = "import")]
169#[doc(inline)]
170pub use self::import::import_images;
171#[cfg(feature = "import")]
172#[doc(inline)]
173pub use self::import::import_slice;
174#[doc(inline)]
175pub use self::material::Material;
176#[doc(inline)]
177pub use self::mesh::{Attribute, Mesh, Primitive, Semantic};
178#[doc(inline)]
179pub use self::scene::{Node, Scene};
180#[doc(inline)]
181pub use self::skin::Skin;
182#[doc(inline)]
183pub use self::texture::Texture;
184
185use std::path::Path;
186use std::{fs, io, ops, result};
187
188pub(crate) trait Normalize<T> {
189    fn normalize(self) -> T;
190}
191
192/// Result type for convenience.
193pub type Result<T> = result::Result<T, Error>;
194
195/// Represents a runtime error.
196#[derive(Debug)]
197pub enum Error {
198    /// Base 64 decoding error.
199    #[cfg(feature = "import")]
200    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
201    Base64(base64::DecodeError),
202
203    /// GLB parsing error.
204    Binary(binary::Error),
205
206    /// Buffer length does not match expected length.
207    #[cfg(feature = "import")]
208    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
209    BufferLength {
210        /// The index of the offending buffer.
211        buffer: usize,
212
213        /// The expected buffer length in bytes.
214        expected: usize,
215
216        /// The number of bytes actually available.
217        actual: usize,
218    },
219
220    /// JSON deserialization error.
221    Deserialize(json::Error),
222
223    /// Standard I/O error.
224    Io(std::io::Error),
225
226    /// Image decoding error.
227    #[cfg(feature = "import")]
228    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
229    Image(image_crate::ImageError),
230
231    /// The `BIN` chunk of binary glTF is referenced but does not exist.
232    #[cfg(feature = "import")]
233    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
234    MissingBlob,
235
236    /// An external file is referenced in a slice only import without path
237    #[cfg(feature = "import")]
238    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
239    ExternalReferenceInSliceImport,
240
241    /// Unsupported image encoding.
242    #[cfg(feature = "import")]
243    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
244    UnsupportedImageEncoding,
245
246    /// Unsupported image format.
247    #[cfg(feature = "import")]
248    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
249    UnsupportedImageFormat(image_crate::DynamicImage),
250
251    /// Unsupported URI scheme.
252    #[cfg(feature = "import")]
253    #[cfg_attr(docsrs, doc(cfg(feature = "import")))]
254    UnsupportedScheme,
255
256    /// glTF validation error.
257    Validation(Vec<(json::Path, json::validation::Error)>),
258}
259
260/// glTF JSON wrapper plus binary payload.
261#[derive(Clone, Debug)]
262pub struct Gltf {
263    /// The glTF JSON wrapper.
264    pub document: Document,
265
266    /// The glTF binary payload in the case of binary glTF.
267    pub blob: Option<Vec<u8>>,
268}
269
270/// glTF JSON wrapper.
271#[derive(Clone, Debug)]
272pub struct Document(json::Root);
273
274impl Gltf {
275    /// Convenience function that loads glTF from the file system.
276    pub fn open<P>(path: P) -> Result<Self>
277    where
278        P: AsRef<Path>,
279    {
280        let file = fs::File::open(path)?;
281        let reader = io::BufReader::new(file);
282        let gltf = Self::from_reader(reader)?;
283        Ok(gltf)
284    }
285
286    /// Loads glTF from a reader without performing validation checks.
287    pub fn from_reader_without_validation<R>(mut reader: R) -> Result<Self>
288    where
289        R: io::Read + io::Seek,
290    {
291        let mut magic = [0u8; 4];
292        reader.read_exact(&mut magic)?;
293        reader.seek(io::SeekFrom::Current(-4))?;
294        let (json, blob): (json::Root, Option<Vec<u8>>);
295        if magic.starts_with(b"glTF") {
296            let mut glb = binary::Glb::from_reader(reader)?;
297            // TODO: use `json::from_reader` instead of `json::from_slice`
298            json = json::deserialize::from_slice(&glb.json)?;
299            blob = glb.bin.take().map(|x| x.into_owned());
300        } else {
301            json = json::deserialize::from_reader(reader)?;
302            blob = None;
303        };
304        let document = Document::from_json_without_validation(json);
305        Ok(Gltf { document, blob })
306    }
307
308    /// Loads glTF from a reader.
309    pub fn from_reader<R>(reader: R) -> Result<Self>
310    where
311        R: io::Read + io::Seek,
312    {
313        let gltf = Self::from_reader_without_validation(reader)?;
314        gltf.document.validate()?;
315        Ok(gltf)
316    }
317
318    /// Loads glTF from a slice of bytes without performing validation
319    /// checks.
320    pub fn from_slice_without_validation(slice: &[u8]) -> Result<Self> {
321        let (json, blob): (json::Root, Option<Vec<u8>>);
322        if slice.starts_with(b"glTF") {
323            let mut glb = binary::Glb::from_slice(slice)?;
324            json = json::deserialize::from_slice(&glb.json)?;
325            blob = glb.bin.take().map(|x| x.into_owned());
326        } else {
327            json = json::deserialize::from_slice(slice)?;
328            blob = None;
329        };
330        let document = Document::from_json_without_validation(json);
331        Ok(Gltf { document, blob })
332    }
333
334    /// Loads glTF from a slice of bytes.
335    pub fn from_slice(slice: &[u8]) -> Result<Self> {
336        let gltf = Self::from_slice_without_validation(slice)?;
337        gltf.document.validate()?;
338        Ok(gltf)
339    }
340}
341
342impl ops::Deref for Gltf {
343    type Target = Document;
344    fn deref(&self) -> &Self::Target {
345        &self.document
346    }
347}
348
349impl ops::DerefMut for Gltf {
350    fn deref_mut(&mut self) -> &mut Self::Target {
351        &mut self.document
352    }
353}
354
355impl Document {
356    /// Loads glTF from pre-deserialized JSON.
357    pub fn from_json(json: json::Root) -> Result<Self> {
358        let document = Self::from_json_without_validation(json);
359        document.validate()?;
360        Ok(document)
361    }
362
363    /// Loads glTF from pre-deserialized JSON without performing
364    /// validation checks.
365    pub fn from_json_without_validation(json: json::Root) -> Self {
366        Document(json)
367    }
368
369    /// Unwraps the glTF document.
370    pub fn into_json(self) -> json::Root {
371        self.0
372    }
373
374    /// Unwraps the glTF document, without consuming it.
375    pub fn as_json(&self) -> &json::Root {
376        &self.0
377    }
378
379    /// Perform validation checks on loaded glTF.
380    pub(crate) fn validate(&self) -> Result<()> {
381        use json::validation::Validate;
382        let mut errors = Vec::new();
383        self.0
384            .validate(&self.0, json::Path::new, &mut |path, error| {
385                errors.push((path(), error))
386            });
387        if errors.is_empty() {
388            Ok(())
389        } else {
390            Err(Error::Validation(errors))
391        }
392    }
393
394    /// Returns an `Iterator` that visits the accessors of the glTF asset.
395    pub fn accessors(&self) -> iter::Accessors<'_> {
396        iter::Accessors {
397            iter: self.0.accessors.iter().enumerate(),
398            document: self,
399        }
400    }
401
402    /// Returns an `Iterator` that visits the animations of the glTF asset.
403    pub fn animations(&self) -> iter::Animations<'_> {
404        iter::Animations {
405            iter: self.0.animations.iter().enumerate(),
406            document: self,
407        }
408    }
409
410    /// Returns an `Iterator` that visits the pre-loaded buffers of the glTF asset.
411    pub fn buffers(&self) -> iter::Buffers<'_> {
412        iter::Buffers {
413            iter: self.0.buffers.iter().enumerate(),
414            document: self,
415        }
416    }
417
418    /// Returns an `Iterator` that visits the cameras of the glTF asset.
419    pub fn cameras(&self) -> iter::Cameras<'_> {
420        iter::Cameras {
421            iter: self.0.cameras.iter().enumerate(),
422            document: self,
423        }
424    }
425
426    /// Returns the default scene, if provided.
427    pub fn default_scene(&self) -> Option<Scene<'_>> {
428        self.0
429            .scene
430            .as_ref()
431            .map(|index| self.scenes().nth(index.value()).unwrap())
432    }
433
434    /// Returns the extensions referenced in this .document file.
435    pub fn extensions_used(&self) -> iter::ExtensionsUsed<'_> {
436        iter::ExtensionsUsed(self.0.extensions_used.iter())
437    }
438
439    /// Returns the extensions required to load and render this asset.
440    pub fn extensions_required(&self) -> iter::ExtensionsRequired<'_> {
441        iter::ExtensionsRequired(self.0.extensions_required.iter())
442    }
443
444    /// Returns an `Iterator` that visits the pre-loaded images of the glTF asset.
445    pub fn images(&self) -> iter::Images<'_> {
446        iter::Images {
447            iter: self.0.images.iter().enumerate(),
448            document: self,
449        }
450    }
451
452    /// Returns extension data unknown to this crate version.
453    #[cfg(feature = "extensions")]
454    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
455    pub fn extensions(&self) -> Option<&Map<String, Value>> {
456        let root = self.0.extensions.as_ref()?;
457        Some(&root.others)
458    }
459
460    /// Queries extension data unknown to this crate version.
461    #[cfg(feature = "extensions")]
462    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
463    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
464        let root = self.0.extensions.as_ref()?;
465        root.others.get(ext_name)
466    }
467
468    /// Returns an `Iterator` that visits the lights of the glTF asset as defined by the
469    /// `KHR_lights_punctual` extension.
470    #[cfg(feature = "KHR_lights_punctual")]
471    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
472    pub fn lights(&self) -> Option<iter::Lights> {
473        let iter = self
474            .0
475            .extensions
476            .as_ref()?
477            .khr_lights_punctual
478            .as_ref()?
479            .lights
480            .iter()
481            .enumerate();
482
483        Some(iter::Lights {
484            iter,
485            document: self,
486        })
487    }
488
489    /// Returns an `Iterator` that visits the variants of the glTF asset as defined by the
490    /// `KHR_materials_variants` extension.
491    #[cfg(feature = "KHR_materials_variants")]
492    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_variants")))]
493    pub fn variants(&self) -> Option<iter::Variants> {
494        let iter = self
495            .0
496            .extensions
497            .as_ref()?
498            .khr_materials_variants
499            .as_ref()?
500            .variants
501            .iter()
502            .enumerate();
503
504        Some(iter::Variants {
505            iter,
506            document: self,
507        })
508    }
509
510    /// Returns an `Iterator` that visits the materials of the glTF asset.
511    pub fn materials(&self) -> iter::Materials<'_> {
512        iter::Materials {
513            iter: self.0.materials.iter().enumerate(),
514            document: self,
515        }
516    }
517
518    /// Returns an `Iterator` that visits the meshes of the glTF asset.
519    pub fn meshes(&self) -> iter::Meshes<'_> {
520        iter::Meshes {
521            iter: self.0.meshes.iter().enumerate(),
522            document: self,
523        }
524    }
525
526    /// Returns an `Iterator` that visits the nodes of the glTF asset.
527    pub fn nodes(&self) -> iter::Nodes<'_> {
528        iter::Nodes {
529            iter: self.0.nodes.iter().enumerate(),
530            document: self,
531        }
532    }
533
534    /// Returns an `Iterator` that visits the samplers of the glTF asset.
535    pub fn samplers(&self) -> iter::Samplers<'_> {
536        iter::Samplers {
537            iter: self.0.samplers.iter().enumerate(),
538            document: self,
539        }
540    }
541
542    /// Returns an `Iterator` that visits the scenes of the glTF asset.
543    pub fn scenes(&self) -> iter::Scenes<'_> {
544        iter::Scenes {
545            iter: self.0.scenes.iter().enumerate(),
546            document: self,
547        }
548    }
549
550    /// Returns an `Iterator` that visits the skins of the glTF asset.
551    pub fn skins(&self) -> iter::Skins<'_> {
552        iter::Skins {
553            iter: self.0.skins.iter().enumerate(),
554            document: self,
555        }
556    }
557
558    /// Returns an `Iterator` that visits the textures of the glTF asset.
559    pub fn textures(&self) -> iter::Textures<'_> {
560        iter::Textures {
561            iter: self.0.textures.iter().enumerate(),
562            document: self,
563        }
564    }
565
566    /// Returns an `Iterator` that visits the pre-loaded buffer views of the glTF
567    /// asset.
568    pub fn views(&self) -> iter::Views<'_> {
569        iter::Views {
570            iter: self.0.buffer_views.iter().enumerate(),
571            document: self,
572        }
573    }
574}
575
576impl std::fmt::Display for Error {
577    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
578        match self {
579            #[cfg(feature = "import")]
580            Error::Base64(ref e) => e.fmt(f),
581            Error::Binary(ref e) => e.fmt(f),
582            #[cfg(feature = "import")]
583            Error::BufferLength {
584                buffer,
585                expected,
586                actual,
587            } => {
588                write!(
589                    f,
590                    "buffer {}: expected {} bytes but received {} bytes",
591                    buffer, expected, actual
592                )
593            }
594            Error::Deserialize(ref e) => e.fmt(f),
595            Error::Io(ref e) => e.fmt(f),
596            #[cfg(feature = "import")]
597            Error::Image(ref e) => e.fmt(f),
598            #[cfg(feature = "import")]
599            Error::MissingBlob => write!(f, "missing binary portion of binary glTF"),
600            #[cfg(feature = "import")]
601            Error::ExternalReferenceInSliceImport => {
602                write!(f, "external reference in slice only import")
603            }
604            #[cfg(feature = "import")]
605            Error::UnsupportedImageEncoding => write!(f, "unsupported image encoding"),
606            #[cfg(feature = "import")]
607            Error::UnsupportedImageFormat(image) => {
608                write!(f, "unsupported image format: {:?}", image.color())
609            }
610            #[cfg(feature = "import")]
611            Error::UnsupportedScheme => write!(f, "unsupported URI scheme"),
612            Error::Validation(ref xs) => {
613                write!(f, "invalid glTF:")?;
614                for (ref path, ref error) in xs {
615                    write!(f, " {}: {};", path, error)?;
616                }
617                Ok(())
618            }
619        }
620    }
621}
622
623impl std::error::Error for Error {}
624
625impl From<binary::Error> for Error {
626    fn from(err: binary::Error) -> Self {
627        Error::Binary(err)
628    }
629}
630
631impl From<std::io::Error> for Error {
632    fn from(err: std::io::Error) -> Self {
633        Error::Io(err)
634    }
635}
636
637#[cfg(feature = "import")]
638impl From<image_crate::ImageError> for Error {
639    fn from(err: image_crate::ImageError) -> Self {
640        Error::Image(err)
641    }
642}
643
644impl From<json::Error> for Error {
645    fn from(err: json::Error) -> Self {
646        Error::Deserialize(err)
647    }
648}
649
650impl From<Vec<(json::Path, json::validation::Error)>> for Error {
651    fn from(errs: Vec<(json::Path, json::validation::Error)>) -> Self {
652        Error::Validation(errs)
653    }
654}
655
656impl Normalize<i8> for i8 {
657    fn normalize(self) -> i8 {
658        self
659    }
660}
661
662impl Normalize<u8> for i8 {
663    fn normalize(self) -> u8 {
664        self.max(0) as u8 * 2
665    }
666}
667
668impl Normalize<i16> for i8 {
669    fn normalize(self) -> i16 {
670        self as i16 * 0x100
671    }
672}
673
674impl Normalize<u16> for i8 {
675    fn normalize(self) -> u16 {
676        self.max(0) as u16 * 0x200
677    }
678}
679
680impl Normalize<f32> for i8 {
681    fn normalize(self) -> f32 {
682        (self as f32 * 127.0_f32.recip()).max(-1.0)
683    }
684}
685
686impl Normalize<i8> for u8 {
687    fn normalize(self) -> i8 {
688        (self / 2) as i8
689    }
690}
691
692impl Normalize<u8> for u8 {
693    fn normalize(self) -> u8 {
694        self
695    }
696}
697
698impl Normalize<i16> for u8 {
699    fn normalize(self) -> i16 {
700        self as i16 * 0x80
701    }
702}
703
704impl Normalize<u16> for u8 {
705    fn normalize(self) -> u16 {
706        self as u16 * 0x100
707    }
708}
709
710impl Normalize<f32> for u8 {
711    fn normalize(self) -> f32 {
712        self as f32 * 255.0_f32.recip()
713    }
714}
715
716impl Normalize<i8> for i16 {
717    fn normalize(self) -> i8 {
718        (self / 0x100) as i8
719    }
720}
721
722impl Normalize<u8> for i16 {
723    fn normalize(self) -> u8 {
724        (self.max(0) / 0x80) as u8
725    }
726}
727
728impl Normalize<i16> for i16 {
729    fn normalize(self) -> i16 {
730        self
731    }
732}
733
734impl Normalize<u16> for i16 {
735    fn normalize(self) -> u16 {
736        self.max(0) as u16 * 2
737    }
738}
739
740impl Normalize<f32> for i16 {
741    fn normalize(self) -> f32 {
742        (self as f32 * 32767.0_f32.recip()).max(-1.0)
743    }
744}
745
746impl Normalize<i8> for u16 {
747    fn normalize(self) -> i8 {
748        (self / 0x200) as i8
749    }
750}
751
752impl Normalize<u8> for u16 {
753    fn normalize(self) -> u8 {
754        (self / 0x100) as u8
755    }
756}
757
758impl Normalize<i16> for u16 {
759    fn normalize(self) -> i16 {
760        (self / 2) as i16
761    }
762}
763
764impl Normalize<u16> for u16 {
765    fn normalize(self) -> u16 {
766        self
767    }
768}
769
770impl Normalize<f32> for u16 {
771    fn normalize(self) -> f32 {
772        self as f32 * 65535.0_f32.recip()
773    }
774}
775
776impl Normalize<i8> for f32 {
777    fn normalize(self) -> i8 {
778        (self * 127.0) as i8
779    }
780}
781
782impl Normalize<u8> for f32 {
783    fn normalize(self) -> u8 {
784        (self.max(0.0) * 255.0) as u8
785    }
786}
787
788impl Normalize<i16> for f32 {
789    fn normalize(self) -> i16 {
790        (self * 32767.0) as i16
791    }
792}
793
794impl Normalize<u16> for f32 {
795    fn normalize(self) -> u16 {
796        (self.max(0.0) * 65535.0) as u16
797    }
798}
799
800impl Normalize<f32> for f32 {
801    fn normalize(self) -> f32 {
802        self
803    }
804}
805
806impl<U, T> Normalize<[T; 2]> for [U; 2]
807where
808    U: Normalize<T> + Copy,
809{
810    fn normalize(self) -> [T; 2] {
811        [self[0].normalize(), self[1].normalize()]
812    }
813}
814
815impl<U, T> Normalize<[T; 3]> for [U; 3]
816where
817    U: Normalize<T> + Copy,
818{
819    fn normalize(self) -> [T; 3] {
820        [
821            self[0].normalize(),
822            self[1].normalize(),
823            self[2].normalize(),
824        ]
825    }
826}
827
828impl<U, T> Normalize<[T; 4]> for [U; 4]
829where
830    U: Normalize<T> + Copy,
831{
832    fn normalize(self) -> [T; 4] {
833        [
834            self[0].normalize(),
835            self[1].normalize(),
836            self[2].normalize(),
837            self[3].normalize(),
838        ]
839    }
840}