gltf_json/extensions/
scene.rs

1use gltf_derive::Validate;
2use serde_derive::{Deserialize, Serialize};
3#[cfg(feature = "extensions")]
4use serde_json::{Map, Value};
5
6/// A node in the node hierarchy.  When the node contains `skin`, all
7/// `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes.
8/// A node can have either a `matrix` or any combination of
9/// `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted
10/// to matrices and postmultiplied in the `T * R * S` order to compose the
11/// transformation matrix; first the scale is applied to the vertices, then the
12/// rotation, and then the translation. If none are provided, the transform is the
13/// identity. When a node is targeted for animation (referenced by an
14/// animation.channel.target), only TRS properties may be present; `matrix` will not
15/// be present.
16#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
17pub struct Node {
18    #[cfg(feature = "KHR_lights_punctual")]
19    #[serde(
20        default,
21        rename = "KHR_lights_punctual",
22        skip_serializing_if = "Option::is_none"
23    )]
24    pub khr_lights_punctual: Option<khr_lights_punctual::KhrLightsPunctual>,
25
26    #[cfg(feature = "extensions")]
27    #[serde(default, flatten)]
28    pub others: Map<String, Value>,
29}
30
31#[cfg(feature = "KHR_lights_punctual")]
32pub mod khr_lights_punctual {
33    use crate::validation::{Checked, Error};
34    use crate::{Extras, Index, Path, Root};
35    use gltf_derive::Validate;
36    use serde::{de, ser};
37    use serde_derive::{Deserialize, Serialize};
38    use std::fmt;
39
40    /// All valid light types.
41    pub const VALID_TYPES: &[&str] = &["directional", "point", "spot"];
42
43    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
44    pub struct KhrLightsPunctual {
45        pub light: Index<Light>,
46    }
47
48    /// Specifies the light type.
49    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
50    pub enum Type {
51        /// Directional lights act as though they are infinitely far away and emit light in
52        /// the direction of the local -z axis. This light type inherits the orientation of
53        /// the node that it belongs to; position and scale are ignored except for their
54        /// effect on the inherited node orientation. Because it is at an infinite distance,
55        /// the light is not attenuated. Its intensity is defined in lumens per metre squared,
56        /// or lux (lm/m^2).
57        Directional = 1,
58
59        /// Point lights emit light in all directions from their position in space; rotation
60        /// and scale are ignored except for their effect on the inherited node position. The
61        /// brightness of the light attenuates in a physically correct manner as distance
62        /// increases from the light's position (i.e. brightness goes like the inverse square
63        /// of the distance). Point light intensity is defined in candela, which is lumens per
64        /// square radian (lm/sr)."
65        Point,
66
67        /// Spot lights emit light in a cone in the direction of the local -z axis. The angle
68        /// and falloff of the cone is defined using two numbers, the innerConeAngle and outer
69        /// ConeAngle. As with point lights, the brightness also attenuates in a physically
70        /// correct manner as distance increases from the light's position (i.e. brightness
71        /// goes like the inverse square of the distance). Spot light intensity refers to the
72        /// brightness inside the innerConeAngle (and at the location of the light) and is
73        /// defined in candela, which is lumens per square radian (lm/sr). Engines that don't
74        /// support two angles for spotlights should use outerConeAngle as the spotlight angle
75        /// (leaving innerConeAngle to implicitly be 0).
76        Spot,
77    }
78
79    #[derive(Clone, Debug, Deserialize, Serialize, Validate)]
80    #[gltf(validate_hook = "light_validate_hook")]
81    pub struct Light {
82        /// Color of the light source.
83        #[serde(default = "color_default")]
84        pub color: [f32; 3],
85
86        /// Extension specific data.
87        #[serde(default, skip_serializing_if = "Option::is_none")]
88        pub extensions: Option<std::boxed::Box<serde_json::value::RawValue>>,
89
90        /// Optional application specific data.
91        #[serde(default)]
92        #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
93        #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
94        pub extras: Extras,
95
96        /// Intensity of the light source. `point` and `spot` lights use luminous intensity
97        /// in candela (lm/sr) while `directional` lights use illuminance in lux (lm/m^2).
98        #[serde(default = "intensity_default")]
99        pub intensity: f32,
100
101        /// Optional user-defined name for this object.
102        #[cfg(feature = "names")]
103        #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
104        pub name: Option<String>,
105
106        /// A distance cutoff at which the light's intensity may be considered to have reached
107        /// zero.
108        #[serde(default, skip_serializing_if = "Option::is_none")]
109        pub range: Option<f32>,
110
111        /// Spot light parameters.
112        #[serde(default, skip_serializing_if = "Option::is_none")]
113        pub spot: Option<Spot>,
114
115        /// Specifies the light type.
116        #[serde(rename = "type")]
117        pub type_: Checked<Type>,
118    }
119
120    fn light_validate_hook<P, R>(light: &Light, _root: &Root, path: P, report: &mut R)
121    where
122        P: Fn() -> Path,
123        R: FnMut(&dyn Fn() -> Path, Error),
124    {
125        if let Checked::Valid(ty) = light.type_.as_ref() {
126            if *ty == Type::Spot && light.spot.is_none() {
127                report(&|| path().field("spot"), Error::Missing);
128            }
129        }
130    }
131
132    fn color_default() -> [f32; 3] {
133        [1.0, 1.0, 1.0]
134    }
135
136    fn intensity_default() -> f32 {
137        1.0
138    }
139
140    /// Spot light parameters.
141    #[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
142    #[serde(rename_all = "camelCase")]
143    pub struct Spot {
144        /// Angle in radians from centre of spotlight where falloff begins.
145        #[serde(default)]
146        pub inner_cone_angle: f32,
147
148        /// Angle in radians from centre of spotlight where falloff ends.
149        #[serde(default = "outer_cone_angle_default")]
150        pub outer_cone_angle: f32,
151    }
152
153    fn outer_cone_angle_default() -> f32 {
154        std::f32::consts::FRAC_PI_4
155    }
156
157    impl<'de> de::Deserialize<'de> for Checked<Type> {
158        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
159        where
160            D: de::Deserializer<'de>,
161        {
162            struct Visitor;
163            impl<'de> de::Visitor<'de> for Visitor {
164                type Value = Checked<Type>;
165
166                fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
167                    write!(f, "any of: {:?}", VALID_TYPES)
168                }
169
170                fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
171                where
172                    E: de::Error,
173                {
174                    use self::Type::*;
175                    use crate::validation::Checked::*;
176                    Ok(match value {
177                        "directional" => Valid(Directional),
178                        "point" => Valid(Point),
179                        "spot" => Valid(Spot),
180                        _ => Invalid,
181                    })
182                }
183            }
184            deserializer.deserialize_str(Visitor)
185        }
186    }
187
188    impl ser::Serialize for Type {
189        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190        where
191            S: ser::Serializer,
192        {
193            serializer.serialize_str(match *self {
194                Type::Directional => "directional",
195                Type::Point => "point",
196                Type::Spot => "spot",
197            })
198        }
199    }
200}
201
202#[cfg(feature = "KHR_materials_variants")]
203pub mod khr_materials_variants {
204    use crate::validation::{Error, Validate};
205    use crate::{Path, Root};
206    use serde_derive::{Deserialize, Serialize};
207
208    #[derive(Clone, Debug, Deserialize, Serialize)]
209    pub struct Variant {
210        pub name: String,
211    }
212
213    impl Validate for Variant {
214        fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
215        where
216            P: Fn() -> Path,
217            R: FnMut(&dyn Fn() -> Path, Error),
218        {
219            self.name.validate(root, || path().field("name"), report);
220        }
221    }
222}
223
224/// The root `Node`s of a scene.
225#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
226pub struct Scene {
227    #[cfg(feature = "extensions")]
228    #[serde(default, flatten)]
229    pub others: Map<String, Value>,
230}