Skip to main content

pfx_load/scene/
diff.rs

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}