unlit3d_cli/config.rs
1//! The JSON configuration a render reads and the command line overrides.
2
3use serde::Deserialize;
4use unlit3d::components::Transform;
5
6/// A whole render: what to draw, how to frame it, and how big the image is.
7#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
8#[serde(deny_unknown_fields, default)]
9pub struct Config {
10 /// The image size, the render size and the viewport scaling.
11 pub output: OutputConfig,
12 /// The camera the documents are seen through.
13 pub camera: CameraConfig,
14 /// The glTF documents to draw, in order.
15 pub documents: Vec<DocumentConfig>,
16}
17
18/// The image size, the render size and the viewport scaling.
19#[derive(Clone, Debug, PartialEq, Deserialize)]
20#[serde(deny_unknown_fields, default)]
21pub struct OutputConfig {
22 /// The output image size in pixels, as [width, height].
23 ///
24 /// Defaults to render_size when absent, so at least one of the two must be
25 /// present.
26 pub size: Option<(u32, u32)>,
27 /// The render size the camera and viewport are based on, as [width, height].
28 ///
29 /// Defaults to size when absent. The viewport is this size scaled by scale
30 /// and centred in the output.
31 pub render_size: Option<(u32, u32)>,
32 /// The factors scaling the render size into the output size, as
33 /// [scale_x, scale_y]. Each must be positive.
34 pub scale: (f32, f32),
35 /// The multisample count of the render target: 1, 2, 4 or 8.
36 pub samples: u32,
37 /// Whether the render target has a depth buffer.
38 pub depth: bool,
39 /// The clear colour as [red, green, blue, alpha], each in 0..=1.
40 pub clear: [f64; 4],
41}
42
43impl Default for OutputConfig {
44 fn default() -> Self {
45 Self {
46 size: None,
47 render_size: None,
48 scale: (1.0, 1.0),
49 samples: 1,
50 depth: true,
51 clear: [0.0, 0.0, 0.0, 1.0],
52 }
53 }
54}
55
56/// The camera the documents are seen through.
57#[derive(Clone, Debug, PartialEq, Deserialize)]
58#[serde(deny_unknown_fields, default)]
59pub struct CameraConfig {
60 /// The eye position, as [x, y, z].
61 pub eye: [f32; 3],
62 /// The target position, as [x, y, z].
63 pub target: [f32; 3],
64 /// The up vector, as [x, y, z].
65 pub up: [f32; 3],
66 /// The vertical field of view in degrees.
67 pub fov_y: f32,
68 /// The near plane distance.
69 pub z_near: f32,
70 /// A view (world-to-view) matrix in column-major order.
71 ///
72 /// Set together with the projection matrix, these two override eye,
73 /// target, up, fov_y and z_near when present. The camera keeps its view
74 /// and projection apart, and a single combined matrix cannot be split back
75 /// into them, so both must be given.
76 pub view: Option<[f32; 16]>,
77 /// A projection (view-to-clip) matrix in column-major order.
78 ///
79 /// The counterpart of the view matrix; both are needed together.
80 pub projection: Option<[f32; 16]>,
81}
82
83impl Default for CameraConfig {
84 fn default() -> Self {
85 Self {
86 eye: [0.0, 1.2, 3.2],
87 target: [0.0, 0.2, 0.0],
88 up: [0.0, 1.0, 0.0],
89 fov_y: 60.0,
90 z_near: 0.1,
91 view: None,
92 projection: None,
93 }
94 }
95}
96
97/// One glTF document and how it enters the scene.
98#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
99#[serde(deny_unknown_fields, default)]
100pub struct DocumentConfig {
101 /// The path to the .gltf or .glb file.
102 pub path: String,
103 /// The transform every spawned node of the document is placed with.
104 pub placement: Option<PlacementConfig>,
105 /// The animation to sample, by index or by name.
106 pub animation: Option<AnimationRef>,
107 /// The animation time in seconds.
108 pub time: f32,
109}
110
111/// A placement transform for a document's nodes.
112#[derive(Clone, Debug, PartialEq, Deserialize)]
113#[serde(deny_unknown_fields, default)]
114pub struct PlacementConfig {
115 /// The translation, as [x, y, z].
116 pub translation: [f32; 3],
117 /// The rotation quaternion, as [x, y, z, w].
118 pub rotation: [f32; 4],
119 /// The scale, as [x, y, z].
120 pub scale: [f32; 3],
121}
122
123impl Default for PlacementConfig {
124 fn default() -> Self {
125 Self {
126 translation: [0.0, 0.0, 0.0],
127 rotation: [0.0, 0.0, 0.0, 1.0],
128 scale: [1.0, 1.0, 1.0],
129 }
130 }
131}
132
133impl PlacementConfig {
134 /// The transform this placement describes.
135 #[must_use]
136 pub fn transform(&self) -> Transform {
137 Transform {
138 translation: glam::Vec3::from(self.translation),
139 rotation: glam::Quat::from_xyzw(
140 self.rotation[0],
141 self.rotation[1],
142 self.rotation[2],
143 self.rotation[3],
144 ),
145 scale: glam::Vec3::from(self.scale),
146 }
147 }
148}
149
150/// Names an animation of a document, by index or by name.
151#[derive(Clone, Debug, PartialEq, Deserialize)]
152#[serde(untagged)]
153pub enum AnimationRef {
154 /// The animation's index in the document.
155 Index(usize),
156 /// The animation's name.
157 Name(String),
158}