1use std::collections::BTreeMap;
2
3use super::Scene;
4
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6pub struct Changes {
7 pub added: Vec<String>,
8 pub changed: Vec<String>,
9 pub removed: Vec<String>,
10}
11
12impl Changes {
13 pub fn is_empty(&self) -> bool {
14 self.added.is_empty() && self.changed.is_empty() && self.removed.is_empty()
15 }
16
17 pub fn by<T>(
18 older: &BTreeMap<String, T>,
19 newer: &BTreeMap<String, T>,
20 same: impl Fn(&T, &T) -> bool,
21 ) -> Self {
22 let mut changes = Self::default();
23 for (name, value) in newer {
24 match older.get(name) {
25 None => changes.added.push(name.clone()),
26 Some(old) if !same(old, value) => changes.changed.push(name.clone()),
27 Some(_) => {}
28 }
29 }
30 for name in older.keys() {
31 if !newer.contains_key(name) {
32 changes.removed.push(name.clone());
33 }
34 }
35 changes
36 }
37}
38
39#[derive(Clone, Debug, Default, PartialEq, Eq)]
40pub struct SceneDiff {
41 pub meshes: Changes,
42 pub materials: Changes,
43 pub objects: Changes,
44 pub lights: Changes,
45 pub emitters: Changes,
46 pub contents: Changes,
47 pub texts: Changes,
48 pub movers: Changes,
49 pub bodies: Changes,
50 pub characters: Changes,
51 pub animations: Changes,
52 pub triggers: Changes,
53 pub layers: bool,
54 pub sounds: Changes,
55 pub order: bool,
56 pub fallback: bool,
57 pub sun: bool,
58 pub sky: bool,
59 pub haze: bool,
60 pub camera: bool,
61 pub finish: bool,
62 pub trace: bool,
63 pub plates: bool,
64 pub physics: bool,
65}
66
67impl SceneDiff {
68 pub fn is_empty(&self) -> bool {
69 self.meshes.is_empty()
70 && self.materials.is_empty()
71 && self.objects.is_empty()
72 && self.lights.is_empty()
73 && self.emitters.is_empty()
74 && self.contents.is_empty()
75 && self.texts.is_empty()
76 && self.movers.is_empty()
77 && self.bodies.is_empty()
78 && self.characters.is_empty()
79 && self.animations.is_empty()
80 && self.triggers.is_empty()
81 && !self.layers
82 && self.sounds.is_empty()
83 && !self.order
84 && !self.fallback
85 && !self.sun
86 && !self.sky
87 && !self.haze
88 && !self.camera
89 && !self.finish
90 && !self.trace
91 && !self.plates
92 && !self.physics
93 }
94
95 pub fn draws(&self) -> bool {
96 !self.meshes.is_empty()
97 || !self.materials.is_empty()
98 || !self.objects.is_empty()
99 || !self.emitters.is_empty()
100 || !self.contents.is_empty()
101 || !self.movers.is_empty()
102 || !self.animations.is_empty()
103 || self.order
104 || self.fallback
105 }
106}
107
108pub(super) fn diff(older: &Scene, newer: &Scene) -> SceneDiff {
109 let objects = |scene: &Scene| -> BTreeMap<String, super::Object> {
110 scene
111 .objects
112 .iter()
113 .map(|object| (object.name.clone(), object.clone()))
114 .collect()
115 };
116 let materials = |scene: &Scene| -> BTreeMap<String, pfx_materials::Material> {
117 scene
118 .library
119 .iter()
120 .map(|(name, material)| (name.to_string(), *material))
121 .collect()
122 };
123 let names = |scene: &Scene| -> Vec<String> {
124 scene
125 .objects
126 .iter()
127 .map(|object| object.name.clone())
128 .collect()
129 };
130 let objects_changes = Changes::by(&objects(older), &objects(newer), |a, b| a == b);
131 SceneDiff {
132 meshes: Changes::by(&older.meshes, &newer.meshes, |a, b| a.hash == b.hash),
133 materials: Changes::by(&materials(older), &materials(newer), |a, b| a == b),
134 order: objects_changes.added.is_empty()
135 && objects_changes.removed.is_empty()
136 && names(older) != names(newer),
137 objects: objects_changes,
138 lights: Changes::by(&older.lights, &newer.lights, |a, b| a == b),
139 emitters: Changes::by(&older.emitters, &newer.emitters, |a, b| a == b),
140 contents: Changes::by(&older.contents, &newer.contents, |a, b| a.hash == b.hash),
141 texts: Changes::by(&older.texts, &newer.texts, |a, b| a == b),
142 movers: Changes::by(&older.movers, &newer.movers, |a, b| a == b),
143 bodies: Changes::by(&older.bodies, &newer.bodies, |a, b| a == b),
144 characters: Changes::by(&older.characters, &newer.characters, |a, b| a == b),
145 animations: Changes::by(&older.animations, &newer.animations, |a, b| a == b),
146 triggers: Changes::by(&older.triggers, &newer.triggers, |a, b| a == b),
147 layers: older.layers != newer.layers || older.body_layers != newer.body_layers,
148 sounds: Changes::by(&older.sounds, &newer.sounds, |a, b| {
149 a.hash == b.hash
150 && a.volume == b.volume
151 && a.pan == b.pan
152 && a.looping == b.looping
153 && a.cue == b.cue
154 && a.object == b.object
155 }),
156 fallback: older.fallback != newer.fallback,
157 sun: older.sun != newer.sun,
158 sky: older.sky != newer.sky,
159 haze: older.haze != newer.haze,
160 camera: older.camera != newer.camera,
161 finish: older.finish != newer.finish,
162 trace: older.trace != newer.trace,
163 plates: older.plates != newer.plates,
164 physics: older.physics != newer.physics,
165 }
166}