forked from StudioInfinity/dyna3
Introduce ghost mode
Elements in ghost mode are intangible. Spheres in ghost mode are also more transparent. Points in ghost mode should probably be more transparent too, but that hasn't been implemented yet.
This commit is contained in:
parent
ba1d87812f
commit
fc230e4993
4 changed files with 40 additions and 7 deletions
|
@ -90,6 +90,10 @@ summary > div, .regulator {
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.element > input {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.element-switch {
|
.element-switch {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
|
|
|
@ -101,6 +101,7 @@ pub trait Element: Serial + ProblemPoser + DisplayItem {
|
||||||
fn id(&self) -> &String;
|
fn id(&self) -> &String;
|
||||||
fn label(&self) -> &String;
|
fn label(&self) -> &String;
|
||||||
fn representation(&self) -> Signal<DVector<f64>>;
|
fn representation(&self) -> Signal<DVector<f64>>;
|
||||||
|
fn ghost(&self) -> Signal<bool>;
|
||||||
|
|
||||||
// the regulators the element is subject to. the assembly that owns the
|
// the regulators the element is subject to. the assembly that owns the
|
||||||
// element is responsible for keeping this set up to date
|
// element is responsible for keeping this set up to date
|
||||||
|
@ -154,6 +155,7 @@ pub struct Sphere {
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub color: ElementColor,
|
pub color: ElementColor,
|
||||||
pub representation: Signal<DVector<f64>>,
|
pub representation: Signal<DVector<f64>>,
|
||||||
|
pub ghost: Signal<bool>,
|
||||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||||
serial: u64,
|
serial: u64,
|
||||||
column_index: Cell<Option<usize>>
|
column_index: Cell<Option<usize>>
|
||||||
|
@ -173,6 +175,7 @@ impl Sphere {
|
||||||
label: label,
|
label: label,
|
||||||
color: color,
|
color: color,
|
||||||
representation: create_signal(representation),
|
representation: create_signal(representation),
|
||||||
|
ghost: create_signal(false),
|
||||||
regulators: create_signal(BTreeSet::new()),
|
regulators: create_signal(BTreeSet::new()),
|
||||||
serial: Self::next_serial(),
|
serial: Self::next_serial(),
|
||||||
column_index: None.into()
|
column_index: None.into()
|
||||||
|
@ -210,6 +213,10 @@ impl Element for Sphere {
|
||||||
self.representation
|
self.representation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ghost(&self) -> Signal<bool> {
|
||||||
|
self.ghost
|
||||||
|
}
|
||||||
|
|
||||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||||
self.regulators
|
self.regulators
|
||||||
}
|
}
|
||||||
|
@ -244,6 +251,7 @@ pub struct Point {
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub color: ElementColor,
|
pub color: ElementColor,
|
||||||
pub representation: Signal<DVector<f64>>,
|
pub representation: Signal<DVector<f64>>,
|
||||||
|
pub ghost: Signal<bool>,
|
||||||
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
|
||||||
serial: u64,
|
serial: u64,
|
||||||
column_index: Cell<Option<usize>>
|
column_index: Cell<Option<usize>>
|
||||||
|
@ -263,6 +271,7 @@ impl Point {
|
||||||
label,
|
label,
|
||||||
color,
|
color,
|
||||||
representation: create_signal(representation),
|
representation: create_signal(representation),
|
||||||
|
ghost: create_signal(false),
|
||||||
regulators: create_signal(BTreeSet::new()),
|
regulators: create_signal(BTreeSet::new()),
|
||||||
serial: Self::next_serial(),
|
serial: Self::next_serial(),
|
||||||
column_index: None.into()
|
column_index: None.into()
|
||||||
|
@ -296,6 +305,10 @@ impl Element for Point {
|
||||||
self.representation
|
self.representation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ghost(&self) -> Signal<bool> {
|
||||||
|
self.ghost
|
||||||
|
}
|
||||||
|
|
||||||
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
|
||||||
self.regulators
|
self.regulators
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use crate::{
|
||||||
struct SceneSpheres {
|
struct SceneSpheres {
|
||||||
representations: Vec<DVector<f64>>,
|
representations: Vec<DVector<f64>>,
|
||||||
colors: Vec<ElementColor>,
|
colors: Vec<ElementColor>,
|
||||||
|
opacities: Vec<f32>,
|
||||||
highlights: Vec<f32>
|
highlights: Vec<f32>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ impl SceneSpheres {
|
||||||
SceneSpheres {
|
SceneSpheres {
|
||||||
representations: Vec::new(),
|
representations: Vec::new(),
|
||||||
colors: Vec::new(),
|
colors: Vec::new(),
|
||||||
|
opacities: Vec::new(),
|
||||||
highlights: Vec::new()
|
highlights: Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,9 +43,10 @@ impl SceneSpheres {
|
||||||
self.representations.len().try_into().expect("Number of spheres must fit in a 32-bit integer")
|
self.representations.len().try_into().expect("Number of spheres must fit in a 32-bit integer")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, highlight: f32) {
|
fn push(&mut self, representation: DVector<f64>, color: ElementColor, opacity: f32, highlight: f32) {
|
||||||
self.representations.push(representation);
|
self.representations.push(representation);
|
||||||
self.colors.push(color);
|
self.colors.push(color);
|
||||||
|
self.opacities.push(opacity);
|
||||||
self.highlights.push(highlight);
|
self.highlights.push(highlight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,11 +101,16 @@ pub trait DisplayItem {
|
||||||
|
|
||||||
impl DisplayItem for Sphere {
|
impl DisplayItem for Sphere {
|
||||||
fn show(&self, scene: &mut Scene, selected: bool) {
|
fn show(&self, scene: &mut Scene, selected: bool) {
|
||||||
const HIGHLIGHT: f32 = 0.2; /* SCAFFOLDING */
|
/* SCAFFOLDING */
|
||||||
|
const DEFAULT_OPACITY: f32 = 0.5;
|
||||||
|
const GHOST_OPACITY: f32 = 0.2;
|
||||||
|
const HIGHLIGHT: f32 = 0.2;
|
||||||
|
|
||||||
let representation = self.representation.get_clone_untracked();
|
let representation = self.representation.get_clone_untracked();
|
||||||
let color = if selected { self.color.map(|channel| 0.2 + 0.8*channel) } else { self.color };
|
let color = if selected { self.color.map(|channel| 0.2 + 0.8*channel) } else { self.color };
|
||||||
|
let opacity = if self.ghost.get() { GHOST_OPACITY } else { DEFAULT_OPACITY };
|
||||||
let highlight = if selected { 1.0 } else { HIGHLIGHT };
|
let highlight = if selected { 1.0 } else { HIGHLIGHT };
|
||||||
scene.spheres.push(representation, color, highlight);
|
scene.spheres.push(representation, color, opacity, highlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method should be kept synchronized with `sphere_cast` in
|
// this method should be kept synchronized with `sphere_cast` in
|
||||||
|
@ -365,6 +373,7 @@ pub fn Display() -> View {
|
||||||
state.assembly.elements.with(|elts| {
|
state.assembly.elements.with(|elts| {
|
||||||
for elt in elts {
|
for elt in elts {
|
||||||
elt.representation().track();
|
elt.representation().track();
|
||||||
|
elt.ghost().track();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
state.selection.track();
|
state.selection.track();
|
||||||
|
@ -395,7 +404,6 @@ pub fn Display() -> View {
|
||||||
const SHRINKING_SPEED: f64 = 0.15; // in length units per second
|
const SHRINKING_SPEED: f64 = 0.15; // in length units per second
|
||||||
|
|
||||||
// display parameters
|
// display parameters
|
||||||
const OPACITY: f32 = 0.5; /* SCAFFOLDING */
|
|
||||||
const LAYER_THRESHOLD: i32 = 0; /* DEBUG */
|
const LAYER_THRESHOLD: i32 = 0; /* DEBUG */
|
||||||
const DEBUG_MODE: i32 = 0; /* DEBUG */
|
const DEBUG_MODE: i32 = 0; /* DEBUG */
|
||||||
|
|
||||||
|
@ -648,7 +656,7 @@ pub fn Display() -> View {
|
||||||
|
|
||||||
let sphere_color = &mut [0.0; 4];
|
let sphere_color = &mut [0.0; 4];
|
||||||
sphere_color[..3].copy_from_slice(&scene.spheres.colors[n]);
|
sphere_color[..3].copy_from_slice(&scene.spheres.colors[n]);
|
||||||
sphere_color[3] = OPACITY;
|
sphere_color[3] = scene.spheres.opacities[n];
|
||||||
|
|
||||||
ctx.uniform3fv_with_f32_array(
|
ctx.uniform3fv_with_f32_array(
|
||||||
sphere_sp_locs[n].as_ref(),
|
sphere_sp_locs[n].as_ref(),
|
||||||
|
@ -854,7 +862,11 @@ pub fn Display() -> View {
|
||||||
let (dir, pixel_size) = event_dir(&event);
|
let (dir, pixel_size) = event_dir(&event);
|
||||||
console::log_1(&JsValue::from(dir.to_string()));
|
console::log_1(&JsValue::from(dir.to_string()));
|
||||||
let mut clicked: Option<(Rc<dyn Element>, f64)> = None;
|
let mut clicked: Option<(Rc<dyn Element>, f64)> = None;
|
||||||
for elt in state.assembly.elements.get_clone_untracked() {
|
let tangible_elts = state.assembly.elements
|
||||||
|
.get_clone_untracked()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|elt| !elt.ghost().get());
|
||||||
|
for elt in tangible_elts {
|
||||||
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)) {
|
match assembly_to_world.with(|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)) {
|
||||||
Some(depth) => match clicked {
|
Some(depth) => match clicked {
|
||||||
Some((_, best_depth)) => {
|
Some((_, best_depth)) => {
|
||||||
|
|
|
@ -202,7 +202,11 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
|
||||||
) {
|
) {
|
||||||
div(class="element-label") { (label) }
|
div(class="element-label") { (label) }
|
||||||
div(class="element-representation") { (rep_components) }
|
div(class="element-representation") { (rep_components) }
|
||||||
div(class="status")
|
input(
|
||||||
|
r#type="checkbox",
|
||||||
|
bind:checked=element.ghost(),
|
||||||
|
on:click=|event: MouseEvent| event.stop_propagation()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul(class="regulators") {
|
ul(class="regulators") {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue