Skip to content

Commit

Permalink
Expose main rendering parameters to CLI/query/GUI.
Browse files Browse the repository at this point in the history
Fixes #424
  • Loading branch information
Yeicor committed Nov 29, 2024
1 parent 23a4fcb commit 252baf2
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 20 deletions.
10 changes: 9 additions & 1 deletion src/app/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ pub(crate) mod settings;

#[derive(clap::Parser, Debug, Clone, PartialEq, Eq, Default)]
pub struct CliApp {
/// The maximum number of voxels to compute per side of the SDF.
#[clap(long, default_value = "64")]
pub max_voxels_side: usize,
/// The number of passes to load the SDF.
/// Initial passes use a lower resolution to give feedback faster.
#[clap(long, default_value = "2")]
pub loading_passes: usize,
/// The SDF provider to use.
#[clap(subcommand)]
pub sdf_provider: CliSDFProvider,
}
Expand All @@ -20,7 +28,7 @@ impl CliApp {
let (sender_of_updates, receiver_of_updates) = mpsc::channel(16);
app.set_root_sdf_loading_manager(receiver_of_updates);
match self.sdf_provider.clone() {
CliSDFProvider::Demo(s) => app.set_root_sdf(Box::new(s)),
CliSDFProvider::Demo(s) => app.set_root_sdf(Box::new(s), Some(self.max_voxels_side), Some(self.loading_passes)),
CliSDFProvider::Url(watch) => {
load::load_sdf_from_path_or_url(sender_of_updates, watch.url);
}
Expand Down
30 changes: 21 additions & 9 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::rc::Rc;
use std::sync::Arc;

use eframe::{egui, Theme};
use eframe::egui::{Context, Frame, ProgressBar, ScrollArea, Ui, Vec2};
use eframe::egui::collapsing_header::CollapsingState;
use eframe::egui::panel::{Side, TopBottomSide};
use eframe::egui::{Context, Frame, ProgressBar, ScrollArea, Ui, Vec2};
use eframe::{egui, Theme};
use image::EncodableLayout;
use tokio::sync::mpsc::error::TryRecvError;
use tokio::sync::mpsc::Receiver;
Expand All @@ -18,20 +18,20 @@ use crate::app::cli::CliApp;
use crate::app::frameinput::FrameInput;
use crate::cli::env_get;
use crate::sdf::demo::cube::SDFDemoCube;
use crate::sdf::SDFSurface;
use crate::sdf::wasm::load::spawn_async;
use crate::sdf::SDFSurface;

pub mod cli;
pub mod scene;
mod frameinput;
pub mod scene;

/// The main application state and logic.
/// As the application is mostly single-threaded, use RefCell for performance when interior mutability is required.
pub struct SDFViewerApp {
/// If set, indicates the load progress of the SDF in the range [0, 1] and the display text.
pub progress: Option<(f32, String)>,
/// The root SDF surface. This is static as it is generated with Box::leak.
/// This is needed as we may only be rendering a sub-tree of the SDF.
/// This is needed as we may only be rendering a subtree of the SDF.
pub sdf: Rc<Box<dyn SDFSurface>>,
// TODO: A loading (downloading/parsing/compiling wasm) indicator for the user.
/// The SDF for which we are modifying the parameters, if any.
Expand Down Expand Up @@ -97,9 +97,16 @@ impl SDFViewerApp {

/// Updates the root SDF surface and sets the whole surface as the render target.
/// The root SDF must be owned at this point.
pub fn set_root_sdf(&mut self, sdf: Box<dyn SDFSurface>) {
pub fn set_root_sdf(
&mut self,
sdf: Box<dyn SDFSurface>,
max_voxels_side: Option<usize>, // None means keep the current value
loading_passes: Option<usize>, // None means keep the current value
) {
self.sdf = Rc::new(sdf); // Reference counted ownership as we need to share it with the scene renderer.
Self::scene_mut(|scene| scene.set_sdf(Rc::clone(&self.sdf), 64, 2));
Self::scene_mut(|scene| {
scene.set_sdf(Rc::clone(&self.sdf), max_voxels_side, loading_passes)
});
}

/// Updates the root SDF using a promise that will be polled on update.
Expand Down Expand Up @@ -138,7 +145,12 @@ impl SDFViewerApp {
self.sdf_loading = if let Some(mut receiver) = self.sdf_loading.take() {
match receiver.try_recv() {
Ok(new_root_sdf) => {
self.set_root_sdf(new_root_sdf);
let cur_settings = self.app_settings.current();
self.set_root_sdf(
new_root_sdf,
Some(cur_settings.max_voxels_side),
Some(cur_settings.loading_passes),
);
None // Disconnect after the first update (more updates should generate another receiver to display progress)
}
Err(TryRecvError::Empty) => {
Expand Down Expand Up @@ -192,7 +204,7 @@ impl SDFViewerApp {
info!("Rendering only {}", sdf.name());
Self::scene_mut(|scene| {
// Will progressively regenerate the scene in the next frames
scene.set_sdf(Rc::clone(&sdf), 64, 2);
scene.set_sdf(Rc::clone(&sdf), None, None);
});
}
});
Expand Down
31 changes: 24 additions & 7 deletions src/app/scene/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::cmp::max;
use std::rc::Rc;
use std::sync::Arc;
use std::time::Duration;
Expand All @@ -15,8 +16,8 @@ use crate::app::frameinput::FrameInput;
use crate::app::scene::sdf::SDFViewer;
use crate::sdf::SDFSurface;

pub mod sdf;
pub mod camera;
pub mod sdf;

thread_local! {
/// We get a [`glow::Context`] from `eframe`, but we want a [`scene::Context`] for [`SDFViewerAppScene`].
Expand Down Expand Up @@ -76,9 +77,7 @@ impl SDFViewerAppScene {
pub fn read_context_thread_local<R>(
f: impl FnOnce(&mut Self) -> R,
) -> Option<R> {
SCENE.with(|scene| scene.borrow_mut().as_mut().map(|x| {
f(x)
}))
SCENE.with(|scene| scene.borrow_mut().as_mut().map(f))
}

pub fn new(ctx: Context, sdf: Rc<Box<dyn SDFSurface>>) -> Self {
Expand All @@ -98,7 +97,7 @@ impl SDFViewerAppScene {
let mut lights: Vec<Box<dyn Light>> = vec![];

// Create the SDF loader and viewer
let sdf_viewer = SDFViewer::from_bb(&ctx, &sdf.bounding_box(), Some(64), 2);
let sdf_viewer = SDFViewer::from_bb(&ctx, &sdf.bounding_box(), 32, 2);
// sdf_viewer.volume.borrow_mut().material.color = Color::new_opaque(25, 225, 25);
// objects.push(Box::new(Rc::clone(&sdf_viewer.volume)));

Expand Down Expand Up @@ -133,10 +132,28 @@ impl SDFViewerAppScene {
}

/// Updates the SDF to render (and clears all required caches).
pub fn set_sdf(&mut self, sdf: Rc<Box<dyn SDFSurface>>, max_voxels_side: usize, loading_passes: usize) {
pub fn set_sdf(
&mut self,
sdf: Rc<Box<dyn SDFSurface>>,
max_voxels_side: Option<usize>, // None means keep the current value
loading_passes: Option<usize>, // None means keep the current value
) {
let bb = sdf.bounding_box();
self.sdf = sdf;
self.sdf_viewer = SDFViewer::from_bb(&self.ctx, &bb, Some(max_voxels_side), loading_passes);
let max_voxels_side_val = max_voxels_side.unwrap_or_else(|| {
max(
max(self.sdf_viewer.tex0.width, self.sdf_viewer.tex0.height),
self.sdf_viewer.tex0.depth,
) as usize
});
let loading_passes_val = loading_passes
.unwrap_or_else(|| self.sdf_viewer.loading_mgr.step_size.ilog2() as usize);
self.sdf_viewer = SDFViewer::from_bb(
&self.ctx,
&bb,
max_voxels_side_val,
loading_passes_val,
);
}

pub fn render(&mut self, frame_input: FrameInput<'_>, egui_resp: &Response) -> Option<glow::Framebuffer> {
Expand Down
3 changes: 2 additions & 1 deletion src/app/scene/sdf/loading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct LoadingManager {
pub(crate) limits: Vector3<usize>,
/// The current number of indices skipped in each dimension.
/// It explores powers of two, in descending order, stopping at 1.
step_size: usize,
pub(crate) step_size: usize,
/// The next index to return.
next_index: Vector3<usize>,
/// The number of iterations performed in the current pass.
Expand All @@ -29,6 +29,7 @@ impl LoadingManager {
slf.reset(passes);
slf
}

/// Resets the interlacing manager to the first pass.
pub fn reset(&mut self, passes: usize) {
self.step_size = 2usize.pow(passes as u32 - 1);
Expand Down
3 changes: 1 addition & 2 deletions src/app/scene/sdf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ const AIR_DIST: f32 = 1e-1 + 0.001234;

impl SDFViewer {
/// Creates a new SDF viewer for the given bounding box (tries to keep aspect ratio).
pub fn from_bb(ctx: &three_d::Context, bb: &[Vector3<f32>; 2], max_voxels_side: Option<usize>, loading_passes: usize) -> Self {
let max_voxels_side = max_voxels_side.unwrap_or(256);
pub fn from_bb(ctx: &three_d::Context, bb: &[Vector3<f32>; 2], max_voxels_side: usize, loading_passes: usize) -> Self {
let bb_size = bb[1] - bb[0];
let mut voxels = Vector3::new(0usize, 0usize, 0usize);
let max_dim = [bb_size.x, bb_size.y, bb_size.z].iter().enumerate().max_by(
Expand Down

0 comments on commit 252baf2

Please sign in to comment.