Skip to content

Commit

Permalink
render: Report if anything changed in RtRenderer and `UpdatingSpace…
Browse files Browse the repository at this point in the history
…Raytracer`.

This will allow their clients to decide whether to actually re-trace
the scene.
  • Loading branch information
kpreid committed Nov 24, 2024
1 parent 270cad3 commit cf8b77a
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
23 changes: 17 additions & 6 deletions all-is-cubes-render/src/raytracer/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,28 @@ where
/// Update the renderer's internal copy of the scene from the data sources
/// (`Handle<Character>` etc.) it is tracking.
///
/// On success, returns whether any of the scene actually changed.
///
/// Returns [`RenderError::Read`] if said sources are in use.
/// In that case, the renderer is still functional but will have stale data.
///
/// This method is equivalent to [`HeadlessRenderer::update()`] except for
/// fitting the raytracer's needs and capabilities (works with all types;
/// not `async`).
pub fn update(&mut self, cursor: Option<&Cursor>) -> Result<(), RenderError> {
pub fn update(&mut self, cursor: Option<&Cursor>) -> Result<bool, RenderError> {
let mut anything_changed = false;

// TODO: raytracer needs to implement drawing the cursor
self.had_cursor = cursor.is_some();
self.cameras.update();
anything_changed |= self.cameras.update();
self.custom_options_cache = self.custom_options.get();

fn sync_space<D>(
cached_rt: &mut Option<UpdatingSpaceRaytracer<D>>,
optional_space: Option<&Handle<Space>>,
graphics_options_source: &ListenableSource<GraphicsOptions>,
custom_options_source: &ListenableSource<D::Options>,
anything_changed: &mut bool,
) -> Result<(), RenderError>
where
D: RtBlockData<Options: Clone + Sync + 'static>,
Expand All @@ -105,18 +110,19 @@ where
(Some(space), Some(rt)) if space == rt.space() => {}
// Needs replacement
(Some(space), rt) => {
*anything_changed = true;
*rt = Some(UpdatingSpaceRaytracer::new(
space.clone(),
graphics_options_source.clone(),
custom_options_source.clone(),
))
));
}
// Space is None, so drop raytracer if any
(None, c) => *c = None,
}
// Now that we have one if we should have one, update it.
if let Some(rt) = cached_rt {
rt.update().map_err(RenderError::Read)?;
*anything_changed |= rt.update().map_err(RenderError::Read)?;
}
Ok(())
}
Expand All @@ -126,15 +132,17 @@ where
Option::as_ref(&self.cameras.world_space().get()),
&gs,
&self.custom_options,
&mut anything_changed,
)?;
sync_space(
&mut self.rts.ui,
self.cameras.ui_space(),
&gs,
&self.custom_options,
&mut anything_changed,
)?;

Ok(())
Ok(anything_changed)
}

/// Produce an image of the current state of the scene this renderer was created to
Expand Down Expand Up @@ -298,7 +306,10 @@ impl HeadlessRenderer for RtRenderer<()> {
&'a mut self,
cursor: Option<&'a Cursor>,
) -> futures_core::future::BoxFuture<'a, Result<(), RenderError>> {
Box::pin(async move { self.update(cursor) })
Box::pin(async move {
let _anything_changed = self.update(cursor)?;
Ok(())
})
}

fn draw<'a>(
Expand Down
27 changes: 18 additions & 9 deletions all-is-cubes/src/raytracer/updating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,10 @@ where

/// Reads the previously provided [`Space`] and updates the local copy of its contents.
///
/// Returns an error if reading fails.
pub fn update(&mut self) -> Result<(), HandleError> {
/// On success, returns whether any of the scene actually changed.
///
/// Returns an error if reading the [`Space`] fails.
pub fn update(&mut self) -> Result<bool, HandleError> {
// Deadlock safety note:
// If the space is being updated, that will acquire the space's lock and then our
// todo's lock for notifications. Therefore, to avoid deadlock we would need to
Expand All @@ -117,7 +119,7 @@ where
let todo: &mut SrtTodo = &mut self.todo.lock().unwrap();
if todo.is_empty() {
// Nothing to do
return Ok(());
return Ok(false);
}
let space = self.space.read()?;

Expand All @@ -133,7 +135,12 @@ where
);
todo.blocks.clear();
todo.cubes.clear();

Ok(true)
} else {
let mut anything_changed = false;

// TODO: need to listen to the options sources for accurate change detection
let graphics_options = &*self.graphics_options.get();
let custom_options = &*self.custom_options.get();
let options = RtOptionsRef {
Expand All @@ -143,20 +150,22 @@ where

let block_data_slice = space.block_data();
if block_data_slice.len() > self.state.blocks.len() {
anything_changed = true;
for block_data in block_data_slice[self.state.blocks.len()..].iter() {
self.state
.blocks
.push(TracingBlock::from_block(options, block_data));
}
}
for block_index in todo.blocks.drain() {
// TODO: handle extending the vector
anything_changed = true;
let block_index = usize::from(block_index);
self.state.blocks[block_index] =
TracingBlock::from_block(options, &block_data_slice[block_index]);
}

for cube in todo.cubes.drain() {
anything_changed = true;
// TODO: this does 2 cube index calculations instead of the 1 it needs
let block_index = space.get_block_index(cube).unwrap_or(0);
self.state.cubes[cube] = TracingCubeData {
Expand All @@ -165,9 +174,9 @@ where
always_invisible: block_data_slice[block_index as usize].block() == &AIR,
};
}
}

Ok(())
Ok(anything_changed)
}
}
}

Expand Down Expand Up @@ -285,9 +294,9 @@ mod tests {
}
}

fn update_and_assert(&mut self) -> Result<(), HandleError> {
fn update_and_assert(&mut self) -> Result<bool, HandleError> {
self.camera.set_options(self.graphics_options.snapshot());
self.updating.update()?;
let changed = self.updating.update()?;
let image_updating = self
.updating
.get()
Expand All @@ -304,7 +313,7 @@ mod tests {

assert_eq!(image_updating.refmt(&Unquote), image_fresh.refmt(&Unquote));
print!("{image_updating}");
Ok(())
Ok(changed)
}
}

Expand Down

0 comments on commit cf8b77a

Please sign in to comment.