gltf_json/
camera.rs

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