1mod anim;
2mod camera;
3mod control;
4mod data;
5mod ext;
6mod geom;
7mod light;
8mod meta;
9mod scene;
10mod transform;
11
12use crate::*;
13pub use {
14 anim::*, camera::*, control::*, data::*, ext::*, geom::*, light::*, meta::*, scene::*,
15 transform::*,
16};
17
18#[derive(Clone, Debug)]
22pub struct Address(pub String);
23
24impl Display for Address {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 Display::fmt(&self.0, f)
27 }
28}
29
30pub trait ParseLibrary: XNode {
32 const LIBRARY: &'static str;
36
37 fn extract_element(e: &LibraryElement) -> Option<&Library<Self>>;
39
40 fn mk_element(lib: Library<Self>) -> LibraryElement;
42}
43
44#[derive(Clone, Debug)]
46pub struct Library<T> {
47 pub asset: Option<Box<Asset>>,
49 pub items: Vec<T>,
51 pub extra: Vec<Extra>,
53}
54
55impl<T> Library<T> {
56 pub fn new(items: Vec<T>) -> Self {
58 Self {
59 asset: None,
60 items,
61 extra: vec![],
62 }
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.asset.is_none() && self.items.is_empty() && self.extra.is_empty()
68 }
69}
70
71impl<T> From<Vec<T>> for Library<T> {
72 fn from(items: Vec<T>) -> Self {
73 Self::new(items)
74 }
75}
76
77impl<T: ParseLibrary> XNode for Library<T> {
78 const NAME: &'static str = T::LIBRARY;
79 fn parse(element: &Element) -> Result<Self> {
80 debug_assert_eq!(element.name(), Self::NAME);
81 let mut it = element.children().peekable();
82 Ok(Library {
83 asset: Asset::parse_opt_box(&mut it)?,
84 items: T::parse_list(&mut it)?, extra: Extra::parse_many(it)?,
86 })
87 }
88}
89
90impl<T: ParseLibrary> XNodeWrite for Library<T> {
91 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
92 let e = Self::elem();
93 if self.is_empty() {
94 e.end(w)
95 } else {
96 let e = e.start(w)?;
97 self.asset.write_to(w)?;
98 self.items.write_to(w)?;
99 self.extra.write_to(w)?;
100 e.end(w)
101 }
102 }
103}
104
105impl<T: CollectLocalMaps> CollectLocalMaps for Library<T> {
106 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
107 self.items.collect_local_maps(maps)
108 }
109}
110
111macro_rules! mk_libraries {
112 (@mkdoc $($doc:expr, $name:ident, $arg:ident,)*) => {
113 #[derive(Clone, Debug)]
115 pub enum LibraryElement {
116 $(#[doc = $doc] $name(Library<$arg>),)*
117 }
118 };
119 ($($(#[derive(Traversable $(, CollectLocalMaps $($mark:literal)?)?)])?
120 $name:ident($arg:ident) = $s:literal,
121 )*) => {
122 $(
123 $(
124 impl Traversable for $arg {
125 fn traverse<'a, E>(
126 doc: &'a Document,
127 f: impl FnMut(&'a $arg) -> Result<(), E>,
128 ) -> Result<(), E> {
129 doc.iter().try_for_each(f)
130 }
131 }
132
133 $(impl CollectLocalMaps $($mark)? for $arg {
134 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
135 maps.insert(self)
136 }
137 })?
138 )?
139
140 impl ParseLibrary for $arg {
141 const LIBRARY: &'static str = $s;
142
143 fn extract_element(e: &LibraryElement) -> Option<&Library<Self>> {
144 if let LibraryElement::$name(arg) = e {
145 Some(arg)
146 } else {
147 None
148 }
149 }
150
151 fn mk_element(lib: Library<Self>) -> LibraryElement {
152 LibraryElement::$name(lib)
153 }
154 }
155 )*
156
157 mk_libraries! {
158 @mkdoc $(
159 concat!("Declares a module of [`", stringify!($arg), "`] elements."),
160 $name, $arg,
161 )*
162 }
163
164 impl LibraryElement {
165 pub fn parse(e: &Element) -> Result<Option<Self>> {
167 Ok(Some(match e.name() {
168 $($arg::LIBRARY => Self::$name(Library::parse(e)?),)*
169 _ => return Ok(None),
170 }))
171 }
172 }
173
174 impl XNodeWrite for LibraryElement {
175 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
176 match self {
177 $(Self::$name(lib) => lib.write_to(w),)*
178 }
179 }
180 }
181
182 impl CollectLocalMaps for LibraryElement {
183 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
184 match self {
185 $(Self::$name(lib) => lib.collect_local_maps(maps),)*
186 }
187 }
188 }
189 }
190}
191
192mk_libraries! {
193 Animations(Animation) = "library_animations",
194
195 #[derive(Traversable, CollectLocalMaps)]
196 AnimationClips(AnimationClip) = "library_animation_clips",
197
198 #[derive(Traversable, CollectLocalMaps)]
199 Cameras(Camera) = "library_cameras",
200
201 #[derive(Traversable, CollectLocalMaps)]
202 Controllers(Controller) = "library_controllers",
203
204 #[derive(Traversable, CollectLocalMaps)]
205 Effects(Effect) = "library_effects",
206
207 #[derive(Traversable, CollectLocalMaps)]
208 ForceFields(ForceField) = "library_force_fields",
209
210 #[derive(Traversable)]
211 Geometries(Geometry) = "library_geometries",
212
213 #[derive(Traversable, CollectLocalMaps)]
214 Images(Image) = "library_images",
215
216 #[derive(Traversable, CollectLocalMaps)]
217 Lights(Light) = "library_lights",
218
219 #[derive(Traversable, CollectLocalMaps)]
220 Materials(Material) = "library_materials",
221
222 Nodes(Node) = "library_nodes",
223
224 #[derive(Traversable, CollectLocalMaps)]
225 PhysicsMaterials(PhysicsMaterial) = "library_physics_materials",
226
227 #[derive(Traversable, CollectLocalMaps)]
228 PhysicsModels(PhysicsModel) = "library_physics_models",
229
230 #[derive(Traversable, CollectLocalMaps)]
231 PhysicsScenes(PhysicsScene) = "library_physics_scenes",
232
233 #[derive(Traversable, CollectLocalMaps)]
234 VisualScenes(VisualScene) = "library_visual_scenes",
235}
236
237#[derive(Clone, Debug)]
252pub struct Instance<T: Instantiate> {
253 pub sid: Option<String>,
256 pub url: UrlRef<T>,
259 pub name: Option<String>,
261 pub data: T::Data,
263 pub extra: Vec<Extra>,
265}
266
267pub(crate) use private::Instantiate;
268pub(crate) mod private {
269 use super::*;
270 pub trait Instantiate {
272 const INSTANCE: &'static str;
275
276 type Data: XNodeWrite + Default;
278
279 fn parse_data(e: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data>;
282
283 fn write_attr(_: &Self::Data, _: &mut ElemBuilder) {}
285
286 fn is_empty(_: &Self::Data) -> bool;
288 }
289}
290
291impl<T: Instantiate> Instance<T> {
292 pub fn new(url: Url) -> Self {
295 Self {
296 sid: Default::default(),
297 url: Ref::new(url),
298 name: Default::default(),
299 data: Default::default(),
300 extra: Default::default(),
301 }
302 }
303}
304
305impl<T: Instantiate> XNode for Instance<T> {
306 const NAME: &'static str = T::INSTANCE;
307 fn parse(element: &Element) -> Result<Self> {
308 debug_assert_eq!(element.name(), Self::NAME);
309 let mut it = element.children().peekable();
310 Ok(Instance {
311 sid: element.attr("sid").map(Into::into),
312 url: parse_attr(element.attr("url"))?.ok_or("missing url attribute")?,
313 name: element.attr("name").map(Into::into),
314 data: T::parse_data(element, &mut it)?,
315 extra: Extra::parse_many(it)?,
316 })
317 }
318}
319
320impl<T: Instantiate> XNodeWrite for Instance<T> {
321 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
322 let mut e = Self::elem();
323 e.opt_attr("sid", &self.sid);
324 e.print_attr("url", &self.url);
325 e.opt_attr("name", &self.name);
326 T::write_attr(&self.data, &mut e);
327 if T::is_empty(&self.data) && self.extra.is_empty() {
328 e.end(w)
329 } else {
330 let e = e.start(w)?;
331 self.data.write_to(w)?;
332 self.extra.write_to(w)?;
333 e.end(w)
334 }
335 }
336}
337
338impl<T: Instantiate> CollectLocalMaps for Instance<T>
339where
340 T::Data: CollectLocalMaps,
341{
342 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
343 self.data.collect_local_maps(maps);
344 }
345}
346
347pub enum DefInstance<T: Instantiate> {
349 Def(T),
351 Ref(Instance<T>),
353}
354
355impl<T: Instantiate> From<Instance<T>> for DefInstance<T> {
356 fn from(v: Instance<T>) -> Self {
357 Self::Ref(v)
358 }
359}
360
361impl<T: Instantiate> From<T> for DefInstance<T> {
362 fn from(v: T) -> Self {
363 Self::Def(v)
364 }
365}
366
367impl<T: Instantiate + Debug> Debug for DefInstance<T>
368where
369 T::Data: Debug,
370{
371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372 match self {
373 Self::Def(t) => f.debug_tuple("Def").field(t).finish(),
374 Self::Ref(t) => f.debug_tuple("Ref").field(t).finish(),
375 }
376 }
377}
378
379impl<T: Instantiate + Clone> Clone for DefInstance<T>
380where
381 T::Data: Clone,
382{
383 fn clone(&self) -> Self {
384 match self {
385 Self::Def(t) => Self::Def(t.clone()),
386 Self::Ref(t) => Self::Ref(t.clone()),
387 }
388 }
389}
390
391impl<T: Instantiate + XNode> DefInstance<T> {
392 pub(crate) fn parse(e: &Element) -> Result<Option<Self>> {
393 Ok(if e.name() == T::NAME {
394 Some(Self::Def(T::parse(e)?))
395 } else if e.name() == T::INSTANCE {
396 Some(Self::Ref(Instance::parse(e)?))
397 } else {
398 None
399 })
400 }
401}
402
403impl<T: Instantiate + XNodeWrite> XNodeWrite for DefInstance<T> {
404 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
405 match self {
406 DefInstance::Def(e) => e.write_to(w),
407 DefInstance::Ref(e) => e.write_to(w),
408 }
409 }
410}
411
412impl<T: Instantiate + CollectLocalMaps> CollectLocalMaps for DefInstance<T> {
413 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
414 if let DefInstance::Def(t) = self {
415 t.collect_local_maps(maps);
416 }
417 }
418}
419
420macro_rules! basic_instance {
421 ($($ty:ty => $val:expr;)*) => {
422 $(impl Instantiate for $ty {
423 const INSTANCE: &'static str = $val;
424 type Data = ();
425 fn parse_data(_: &Element, _: &mut ElementIter<'_>) -> Result<Self::Data> {
426 Ok(())
427 }
428 fn is_empty(_: &Self::Data) -> bool { true }
429 })*
430 }
431}
432basic_instance! {
433 Animation => "instance_animation";
434 Camera => "instance_camera";
435 ForceField => "instance_force_field";
436 Light => "instance_light";
437 Node => "instance_node";
438 PhysicsMaterial => "instance_physics_material";
439 PhysicsScene => "instance_physics_scene";
440 VisualScene => "instance_visual_scene";
441}