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
8pub const VALID_CAMERA_TYPES: &[&str] = &["perspective", "orthographic"];
10
11#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub enum Type {
14 Perspective = 1,
16
17 Orthographic,
19}
20
21#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
26#[gltf(validate_hook = "camera_validate_hook")]
27pub struct Camera {
28 #[cfg(feature = "names")]
30 #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
31 pub name: Option<String>,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
36 pub orthographic: Option<Orthographic>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
41 pub perspective: Option<Perspective>,
42
43 #[serde(rename = "type")]
45 pub type_: Checked<Type>,
46
47 #[serde(default, skip_serializing_if = "Option::is_none")]
49 pub extensions: Option<extensions::camera::Camera>,
50
51 #[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#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
70pub struct Orthographic {
71 pub xmag: f32,
73
74 pub ymag: f32,
76
77 pub zfar: f32,
79
80 pub znear: f32,
82
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub extensions: Option<extensions::camera::Orthographic>,
86
87 #[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#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
96pub struct Perspective {
97 #[serde(rename = "aspectRatio")]
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub aspect_ratio: Option<f32>,
101
102 pub yfov: f32,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub zfar: Option<f32>,
108
109 pub znear: f32,
111
112 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub extensions: Option<extensions::camera::Perspective>,
115
116 #[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}