openconfiguration/scene.rs
1use openconfiguration_derive::Visitable;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use crate::{
6 package::Package, script::Script, status::Status, support, Camera, CatalogEntry, Commercial,
7 Geometry, Material, Product, Representation,
8};
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Visitable)]
11#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
12#[cfg_attr(feature = "schema", schemars(deny_unknown_fields))]
13#[serde(rename_all = "camelCase")]
14/// The Scene is the central part of an OC data set. Each OC data set
15/// contains exactly one.
16///
17/// A Scene may contain initial product representations and/or updates.
18///
19/// A Scene may contain products that should be inserted instantly, as well
20/// as add-ons to be inserted later on and shown as placeholders before.
21pub struct Scene {
22 /// Reference to the JSON schema.
23 #[serde(rename = "$schema")]
24 #[cfg_attr(feature = "schema", schemars(default = "Scene::schema"))]
25 pub schema: Option<String>,
26 /// The mandatory attribute format must be structured as follows:
27 ///
28 /// "OpenConfiguration_<Major/>.<Minor/> [PRE]"
29 ///
30 /// Legal combinations of <Major/>.<Minor/> are: 1.0, 1.1 and 1.2
31 ///
32 /// The optional postfix " PRE" marks a preliminary format.
33 pub format: String,
34 /// This optional attribute contains informal information about the
35 /// creator of this OC data set.
36 pub creator: Option<String>,
37 /// This optional attribute contains informal information about the
38 /// projects used in this OC data set and its corresponding informal
39 /// versions.
40 pub packages: Option<Vec<Package>>,
41 /// This attribute contains general status information about the Scene contents.
42 pub status: Status,
43 /// The representations of the scene. Legal values are:
44 ///
45 /// "Standard" - Real-time mesh data.
46 ///
47 /// "CAD_BIM" - CAD/BIM volume bodies.
48 ///
49 /// "Photo" - High-resolution mesh data.
50 ///
51 /// This just lists possible usages and can be used for fast filtering,
52 /// it does not influence the actual data. A "Photo" renderer would still use
53 /// meshes attached as geometry.mesh
54 pub representations: Option<Vec<Representation>>,
55 /// This optional attribute may contain the id of a server-side session.
56 pub configuration_id: Option<String>,
57 /// This optional attribute may contain the link of the original configuration.
58 pub configuration_link: Option<String>,
59 /// Optional, embedded catalog.
60 pub catalog: Option<Vec<CatalogEntry>>,
61 /// The optional attribute provides a partial URI to be added to all
62 /// relative asset uris. A valid base path should normally start with
63 /// https:// or file://, and end with either a slash or the path separator character of the operating system.
64 /// "Relative" basePath is always relative to the scene.json path,
65 /// not to an application/deployment specific one!
66 /// example.configurator.com/assets/oc/scene.json containing "tex.jpg"
67 /// basepathes "gfx", "./gfx", "/gfx" are all resolved to the same
68 /// example.configurator.com/assets/oc/gfx/tex.jpg
69 pub base_path: Option<String>,
70 /// The mandatory attribute provides unique content hashes for assets
71 /// that are directly referenced in the OC data set. The specific hash
72 /// algorithm is unspecified. It may be an MD5 hash of the binary
73 /// content for instance. But low-res assets may use the same hash as
74 /// the originals, they are derived from. So, the only operation that is
75 /// legal for hash, is to compare them with an optionally existing one.
76 ///
77 /// All assets should have an entry here as downloaders may iterate through
78 /// this record rather than exploring the other data entities.
79 #[serde(deserialize_with = "crate::utils::deserialize_map_without_null_values")]
80 pub hashes: HashMap<String, String>,
81 /// Redirections maybe needed to convert absolute asset urls into file
82 /// names, especially when compiling a self-contained OC zip.
83 /// The attribute is optional.
84 ///
85 /// Version: OC 1.3
86 #[serde(
87 deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
88 default
89 )]
90 pub redirections: Option<HashMap<String, String>>,
91 /// The optional attribute contains all client-side JavaScript packages.
92 pub scripts: Option<Vec<Script>>,
93 /// The optional attribute provides an embedded geometry index.
94 ///
95 /// IGXC Compatibility: now it's embedded, self-contained geometries
96 /// rather than just geometry names. Thus, separate assignments of
97 /// geometry normal maps, deformations, etc. are removed. Also, the
98 /// embedded geometry definition is optional. There can be external
99 /// geometry definitions, too.
100 #[serde(
101 deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
102 default
103 )]
104 #[visitable(visit_with = "visit_geometries")]
105 pub geometries: Option<HashMap<String, Geometry>>,
106 /// The optional attribute provides links to external geometry indices.
107 /// The key should be a two-level technical namespace to speedup the
108 /// geometry lookup.
109 /// The value must be an absolute or relative URI.
110 /// The content of the value, must be de-serialized as GeometryIndex.
111 ///
112 /// IGXC Compatibility: In IGXC, this concept did not exist.
113 #[serde(
114 deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
115 default
116 )]
117 #[visitable(visit_with = "visit_geometry_indexes")]
118 pub geometry_indexes: Option<HashMap<String, String>>,
119 /// The optional attribute provides an embedded geometry index.
120 ///
121 /// IGXC Compatibility: The embedded material definition is optional.
122 /// There can be external material definitions, too.
123 #[serde(
124 deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
125 default
126 )]
127 #[visitable(visit_with = "visit_materials")]
128 pub materials: Option<HashMap<String, Material>>,
129 /// The optional attribute provides links to external geometry indices.
130 /// The key should be a two-level technical namespace to speedup the
131 /// geometry lookup.
132 /// The value must be an absolute or relative URI.
133 /// The content of the value, must be de-serialized as MaterialIndex.
134 ///
135 /// IGXC Compatibility: In IGXC, this concept did not exist.
136 #[serde(
137 deserialize_with = "crate::utils::deserialize_optional_map_without_null_values",
138 default
139 )]
140 #[visitable(visit_with = "visit_material_indexes")]
141 pub material_indexes: Option<HashMap<String, String>>,
142 /// An optional camera setup to restore the camera in another viewer.
143 pub camera: Option<Camera>,
144 /// The mandatory attribute contains the products to be inserted into/
145 /// updated in the client world.
146 ///
147 /// IGXC Compatibility: in IGXC, there is only one product.
148 pub products: Vec<Product>,
149 /// Commercial products without an own visual representation.
150 ///
151 /// Version: OC 1.3
152 pub com_products: Option<Vec<Commercial>>,
153}
154
155impl Scene {
156 pub const fn schema() -> &'static str {
157 "https://archive.intelligentgraphics.biz/schemas/openconfiguration/scene.json"
158 }
159
160 pub fn current_format() -> String {
161 format!("OpenConfiguration_{}", env!("CARGO_PKG_VERSION"))
162 }
163
164 pub fn new() -> Self {
165 Self::new_with_format(Self::current_format())
166 }
167
168 pub fn new_with_format(format: String) -> Self {
169 Self {
170 schema: Some(Scene::schema().to_owned()),
171 format,
172 creator: Default::default(),
173 packages: Default::default(),
174 status: Default::default(),
175 representations: Default::default(),
176 configuration_id: Default::default(),
177 configuration_link: Default::default(),
178 catalog: Default::default(),
179 base_path: Default::default(),
180 hashes: Default::default(),
181 redirections: Default::default(),
182 scripts: Default::default(),
183 geometries: Default::default(),
184 geometry_indexes: Default::default(),
185 materials: Default::default(),
186 material_indexes: Default::default(),
187 camera: Default::default(),
188 products: Default::default(),
189 com_products: Default::default(),
190 }
191 }
192}
193
194fn visit_geometries(
195 map: &mut Option<HashMap<String, Geometry>>,
196 visitor: &mut dyn support::Visitor,
197) {
198 if let Some(map) = map {
199 for (key, value) in map.iter_mut() {
200 if let Some(ig) = &mut value.ig {
201 visitor.visit_geometry(&key, ig);
202 }
203 support::Visitable::visit_with(value, visitor);
204 }
205 }
206}
207
208fn visit_geometry_indexes(
209 map: &mut Option<HashMap<String, String>>,
210 visitor: &mut dyn support::Visitor,
211) {
212 if let Some(map) = map {
213 for (key, value) in map.iter_mut() {
214 visitor.visit_geometry_index(&key, value);
215 visitor.visit_path(value);
216 }
217 }
218}
219
220fn visit_materials(
221 map: &mut Option<HashMap<String, Material>>,
222 visitor: &mut dyn support::Visitor,
223) {
224 if let Some(map) = map {
225 for (key, value) in map.iter_mut() {
226 if let Some(ig) = &mut value.ig {
227 visitor.visit_material(&key, ig);
228 }
229 support::Visitable::visit_with(value, visitor);
230 }
231 }
232}
233
234fn visit_material_indexes(
235 map: &mut Option<HashMap<String, String>>,
236 visitor: &mut dyn support::Visitor,
237) {
238 if let Some(map) = map {
239 for (key, value) in map.iter_mut() {
240 visitor.visit_material_index(&key, value);
241 visitor.visit_path(value);
242 }
243 }
244}