Skip to content

Commit

Permalink
render: StandardCameras::update() reports whether anything changed.
Browse files Browse the repository at this point in the history
Arguably this should be signaled via a `Notifier` instead, but if we do
that, it would make the most sense to make `StandardCameras` itself a
sort of listenable thing that returns a struct of current state, instead
of its current combination of being both the data and the data source.
For now, this is what will be useful.
  • Loading branch information
kpreid committed Nov 24, 2024
1 parent 637063a commit 270cad3
Showing 1 changed file with 32 additions and 12 deletions.
44 changes: 32 additions & 12 deletions all-is-cubes-render/src/camera/stdcam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,24 @@ impl StandardCameras {
///
/// This should be called at the beginning of each frame or as needed when the
/// cameras are to be used.
pub fn update(&mut self) {
///
/// Returns whether any values actually changed.
/// (This does not include tracking changes to space content — only which part of which spaces
/// are being looked at.)
pub fn update(&mut self) -> bool {
let mut anything_changed = false;

let options_dirty = self.graphics_options_dirty.get_and_clear();
if options_dirty {
anything_changed = true;
self.cameras
.world
.set_options(self.graphics_options.snapshot());
}

let ui_dirty = self.ui_dirty.get_and_clear();
if ui_dirty || options_dirty {
anything_changed = true;
let UiViewState {
space,
view_transform: ui_transform,
Expand All @@ -192,13 +200,15 @@ impl StandardCameras {
// changes.
let viewport_dirty = self.viewport_dirty.get_and_clear();
if viewport_dirty {
anything_changed = true;
let viewport: Viewport = self.viewport_source.snapshot();
// TODO: this should be a Layers::iter_mut() or something
self.cameras.world.set_viewport(viewport);
self.cameras.ui.set_viewport(viewport);
}

if self.character_dirty.get_and_clear() {
anything_changed = true;
self.character = self.character_source.snapshot();
if self.character.is_none() {
// Reset transform so it isn't a *stale* transform.
Expand All @@ -212,28 +222,38 @@ impl StandardCameras {
if let Some(character_handle) = &self.character {
match character_handle.read() {
Ok(character) => {
// TODO: Shouldn't we also grab the character's Space while we
// have the access? Renderers could use that.
self.cameras.world.set_view_transform(character.view());
let view_transform = character.view();
if view_transform != self.cameras.world.view_transform() {
anything_changed = true;
self.cameras.world.set_view_transform(character.view());
}

// TODO: ListenableCell should make this easier and cheaper
if Option::as_ref(&*self.world_space.get()) != Some(&character.space) {
anything_changed = true;

self.world_space.set(Some(character.space.clone()));
}

// Update camera exposure from character.
let old_actual_exposure = self.cameras.world.exposure();
self.cameras
.world
.set_measured_exposure(character.exposure());
anything_changed |= self.cameras.world.exposure() != old_actual_exposure;
}
Err(_) => {
// TODO: set an error flag indicating failure to update
}
}
} else {
if self.world_space.get().is_some() {
anything_changed = true;
self.world_space.set(None);
}
}

anything_changed
}

/// Returns current graphics options as of the last [`update()`](Self::update).
Expand Down Expand Up @@ -397,12 +417,12 @@ mod tests {
);

let world_source = cameras.world_space();
let flag = DirtyFlag::listening(false, &world_source);
let world_flag = DirtyFlag::listening(false, &world_source);
assert_eq!(world_source.snapshot().as_ref(), None);

// No redundant notification when world is absent
cameras.update();
assert!(!flag.get_and_clear());
let changed = cameras.update();
assert_eq!((changed, world_flag.get_and_clear()), (false, false));

// Create a universe with space and character
let mut universe = Universe::new();
Expand All @@ -416,14 +436,14 @@ mod tests {
character_cell.set(Some(character));

// Now the world_source should be reporting the new space
assert!(!flag.get_and_clear());
cameras.update();
assert!(flag.get_and_clear());
assert!(!world_flag.get_and_clear());
let changed = cameras.update();
assert_eq!((changed, world_flag.get_and_clear()), (true, true));
assert_eq!(world_source.snapshot().as_ref(), Some(&space_handle));

// No redundant notification when world is present
cameras.update();
assert!(!flag.get_and_clear());
let changed = cameras.update();
assert_eq!((changed, world_flag.get_and_clear()), (false, false));

// TODO: test further changes
}
Expand Down

0 comments on commit 270cad3

Please sign in to comment.