shine_gltf/
camera.rs

1use crate::validation::{Checked, Error, Validate};
2use crate::{extensions, Path, Root};
3use serde::{de, ser};
4use serde_derive::{Deserialize, Serialize};
5use std::fmt;
6
7/// All valid camera types.
8pub const VALID_CAMERA_TYPES: &[&str] = &["perspective", "orthographic"];
9
10/// Specifies the camera type.
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum Type {
13    /// A perspective projection.
14    Perspective = 1,
15
16    /// An orthographic projection.
17    Orthographic,
18}
19
20/// A camera's projection.
21///
22/// A node can reference a camera to apply a transform to place the camera in the
23/// scene.
24#[derive(Clone, Debug, Deserialize, Serialize)]
25pub struct Camera {
26    /// An orthographic camera containing properties to create an orthographic
27    /// projection matrix.
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub orthographic: Option<Orthographic>,
30
31    /// A perspective camera containing properties to create a perspective
32    /// projection matrix.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub perspective: Option<Perspective>,
35
36    /// Specifies if the camera uses a perspective or orthographic projection.
37    #[serde(rename = "type")]
38    pub type_: Checked<Type>,
39
40    /// Extension specific data.
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub extensions: Option<extensions::camera::Camera>,
43}
44
45/// Values for an orthographic camera.
46#[derive(Clone, Debug, Deserialize, Serialize)]
47pub struct Orthographic {
48    /// The horizontal magnification of the view.
49    pub xmag: f32,
50
51    /// The vertical magnification of the view.
52    pub ymag: f32,
53
54    /// The distance to the far clipping plane.
55    pub zfar: f32,
56
57    /// The distance to the near clipping plane.
58    pub znear: f32,
59
60    /// Extension specific data.
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub extensions: Option<extensions::camera::Orthographic>,
63}
64
65/// Values for a perspective camera.
66#[derive(Clone, Debug, Deserialize, Serialize)]
67pub struct Perspective {
68    /// Aspect ratio of the field of view.
69    #[serde(rename = "aspectRatio")]
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub aspect_ratio: Option<f32>,
72
73    /// The vertical field of view in radians.
74    pub yfov: f32,
75
76    /// The distance to the far clipping plane.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub zfar: Option<f32>,
79
80    /// The distance to the near clipping plane.
81    pub znear: f32,
82
83    /// Extension specific data.
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub extensions: Option<extensions::camera::Perspective>,
86}
87
88impl Validate for Camera {
89    fn validate_minimally<P, R>(&self, root: &Root, path: P, report: &mut R)
90    where
91        P: Fn() -> Path,
92        R: FnMut(&dyn Fn() -> Path, Error),
93    {
94        if self.orthographic.is_none() && self.perspective.is_none() {
95            report(&path, Error::Missing);
96        }
97
98        self.orthographic
99            .validate_minimally(root, || path().field("orthographic"), report);
100        self.perspective
101            .validate_minimally(root, || path().field("perspective"), report);
102        self.type_.validate_minimally(root, || path().field("type"), report);
103        self.extensions
104            .validate_minimally(root, || path().field("extensions"), report);
105    }
106}
107
108impl Validate for Orthographic {
109    fn validate_completely<P, R>(&self, root: &Root, path: P, report: &mut R)
110    where
111        P: Fn() -> Path,
112        R: FnMut(&dyn Fn() -> Path, Error),
113    {
114        if self.znear < 0.0 {
115            report(&path, Error::Invalid);
116        }
117
118        if self.zfar < 0.0 || self.zfar < self.znear {
119            report(&path, Error::Invalid);
120        }
121
122        self.extensions
123            .validate_completely(root, || path().field("extensions"), report);
124    }
125}
126
127impl Validate for Perspective {
128    fn validate_completely<P, R>(&self, root: &Root, path: P, report: &mut R)
129    where
130        P: Fn() -> Path,
131        R: FnMut(&dyn Fn() -> Path, Error),
132    {
133        if let Some(aspect_ratio) = self.aspect_ratio {
134            if aspect_ratio < 0.0 {
135                report(&path, Error::Invalid);
136            }
137        }
138
139        if self.yfov < 0.0 {
140            report(&path, Error::Invalid);
141        }
142
143        if self.znear < 0.0 {
144            report(&path, Error::Invalid);
145        }
146
147        if let Some(zfar) = self.zfar {
148            if zfar < 0.0 || zfar < self.znear {
149                report(&path, Error::Invalid);
150            }
151        }
152
153        self.extensions
154            .validate_completely(root, || path().field("extensions"), report);
155    }
156}
157
158impl<'de> de::Deserialize<'de> for Checked<Type> {
159    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160    where
161        D: de::Deserializer<'de>,
162    {
163        struct Visitor;
164        impl<'de> de::Visitor<'de> for Visitor {
165            type Value = Checked<Type>;
166
167            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168                write!(f, "any of: {:?}", VALID_CAMERA_TYPES)
169            }
170
171            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
172            where
173                E: de::Error,
174            {
175                use self::Type::*;
176                use crate::validation::Checked::*;
177                Ok(match value {
178                    "perspective" => Valid(Perspective),
179                    "orthographic" => Valid(Orthographic),
180                    _ => Invalid,
181                })
182            }
183        }
184        deserializer.deserialize_str(Visitor)
185    }
186}
187
188impl ser::Serialize for Type {
189    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190    where
191        S: ser::Serializer,
192    {
193        match *self {
194            Type::Perspective => serializer.serialize_str("perspective"),
195            Type::Orthographic => serializer.serialize_str("orthographic"),
196        }
197    }
198}