forked from StudioInfinity/dyna3
Introduce ghost mode for elements (#85)
Allows any element to be put in "ghost mode," decreasing its opacity and making it insensitive to click-to-select. Ghost mode is toggled using a checkbox in the outline view. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: StudioInfinity/dyna3#85 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
parent
2adf4669f4
commit
a671a8273a
7 changed files with 77 additions and 31 deletions
|
@ -20,11 +20,23 @@ use crate::{
|
|||
assembly::{Element, ElementColor, ElementMotion, Point, Sphere}
|
||||
};
|
||||
|
||||
// --- color ---
|
||||
|
||||
const COLOR_SIZE: usize = 3;
|
||||
type ColorWithOpacity = [f32; COLOR_SIZE + 1];
|
||||
|
||||
fn combine_channels(color: ElementColor, opacity: f32) -> ColorWithOpacity {
|
||||
let mut color_with_opacity = [0.0; COLOR_SIZE + 1];
|
||||
color_with_opacity[..COLOR_SIZE].copy_from_slice(&color);
|
||||
color_with_opacity[COLOR_SIZE] = opacity;
|
||||
color_with_opacity
|
||||
}
|
||||
|
||||
// --- scene data ---
|
||||
|
||||
struct SceneSpheres {
|
||||
representations: Vec<DVector<f64>>,
|
||||
colors: Vec<ElementColor>,
|
||||
colors_with_opacity: Vec<ColorWithOpacity>,
|
||||
highlights: Vec<f32>
|
||||
}
|
||||
|
||||
|
@ -32,7 +44,7 @@ impl SceneSpheres {
|
|||
fn new() -> SceneSpheres{
|
||||
SceneSpheres {
|
||||
representations: Vec::new(),
|
||||
colors: Vec::new(),
|
||||
colors_with_opacity: Vec::new(),
|
||||
highlights: Vec::new()
|
||||
}
|
||||
}
|
||||
|
@ -41,16 +53,16 @@ impl SceneSpheres {
|
|||
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.colors.push(color);
|
||||
self.colors_with_opacity.push(combine_channels(color, opacity));
|
||||
self.highlights.push(highlight);
|
||||
}
|
||||
}
|
||||
|
||||
struct ScenePoints {
|
||||
representations: Vec<DVector<f64>>,
|
||||
colors: Vec<ElementColor>,
|
||||
colors_with_opacity: Vec<ColorWithOpacity>,
|
||||
highlights: Vec<f32>,
|
||||
selections: Vec<f32>
|
||||
}
|
||||
|
@ -59,15 +71,15 @@ impl ScenePoints {
|
|||
fn new() -> ScenePoints {
|
||||
ScenePoints {
|
||||
representations: Vec::new(),
|
||||
colors: Vec::new(),
|
||||
colors_with_opacity: Vec::new(),
|
||||
highlights: Vec::new(),
|
||||
selections: Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, highlight: f32, selected: bool) {
|
||||
fn push(&mut self, representation: DVector<f64>, color: ElementColor, opacity: f32, highlight: f32, selected: bool) {
|
||||
self.representations.push(representation);
|
||||
self.colors.push(color);
|
||||
self.colors_with_opacity.push(combine_channels(color, opacity));
|
||||
self.highlights.push(highlight);
|
||||
self.selections.push(if selected { 1.0 } else { 0.0 });
|
||||
}
|
||||
|
@ -98,11 +110,16 @@ pub trait DisplayItem {
|
|||
|
||||
impl DisplayItem for Sphere {
|
||||
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 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 };
|
||||
scene.spheres.push(representation, color, highlight);
|
||||
scene.spheres.push(representation, color, opacity, highlight);
|
||||
}
|
||||
|
||||
// this method should be kept synchronized with `sphere_cast` in
|
||||
|
@ -148,11 +165,15 @@ impl DisplayItem for Sphere {
|
|||
|
||||
impl DisplayItem for Point {
|
||||
fn show(&self, scene: &mut Scene, selected: bool) {
|
||||
const HIGHLIGHT: f32 = 0.5; /* SCAFFOLDING */
|
||||
/* SCAFFOLDING */
|
||||
const GHOST_OPACITY: f32 = 0.4;
|
||||
const HIGHLIGHT: f32 = 0.5;
|
||||
|
||||
let representation = self.representation.get_clone_untracked();
|
||||
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 { 1.0 };
|
||||
let highlight = if selected { 1.0 } else { HIGHLIGHT };
|
||||
scene.points.push(representation, color, highlight, selected);
|
||||
scene.points.push(representation, color, opacity, highlight, selected);
|
||||
}
|
||||
|
||||
/* SCAFFOLDING */
|
||||
|
@ -365,6 +386,7 @@ pub fn Display() -> View {
|
|||
state.assembly.elements.with(|elts| {
|
||||
for elt in elts {
|
||||
elt.representation().track();
|
||||
elt.ghost().track();
|
||||
}
|
||||
});
|
||||
state.selection.track();
|
||||
|
@ -395,7 +417,6 @@ pub fn Display() -> View {
|
|||
const SHRINKING_SPEED: f64 = 0.15; // in length units per second
|
||||
|
||||
// display parameters
|
||||
const OPACITY: f32 = 0.5; /* SCAFFOLDING */
|
||||
const LAYER_THRESHOLD: i32 = 0; /* DEBUG */
|
||||
const DEBUG_MODE: i32 = 0; /* DEBUG */
|
||||
|
||||
|
@ -469,7 +490,6 @@ pub fn Display() -> View {
|
|||
);
|
||||
let resolution_loc = ctx.get_uniform_location(&sphere_program, "resolution");
|
||||
let shortdim_loc = ctx.get_uniform_location(&sphere_program, "shortdim");
|
||||
let opacity_loc = ctx.get_uniform_location(&sphere_program, "opacity");
|
||||
let layer_threshold_loc = ctx.get_uniform_location(&sphere_program, "layer_threshold");
|
||||
let debug_mode_loc = ctx.get_uniform_location(&sphere_program, "debug_mode");
|
||||
|
||||
|
@ -654,9 +674,9 @@ pub fn Display() -> View {
|
|||
sphere_lt_locs[n].as_ref(),
|
||||
v.rows(3, 2).as_slice()
|
||||
);
|
||||
ctx.uniform3fv_with_f32_array(
|
||||
ctx.uniform4fv_with_f32_array(
|
||||
sphere_color_locs[n].as_ref(),
|
||||
&scene.spheres.colors[n]
|
||||
&scene.spheres.colors_with_opacity[n]
|
||||
);
|
||||
ctx.uniform1f(
|
||||
sphere_highlight_locs[n].as_ref(),
|
||||
|
@ -665,7 +685,6 @@ pub fn Display() -> View {
|
|||
}
|
||||
|
||||
// pass the display parameters
|
||||
ctx.uniform1f(opacity_loc.as_ref(), OPACITY);
|
||||
ctx.uniform1i(layer_threshold_loc.as_ref(), LAYER_THRESHOLD);
|
||||
ctx.uniform1i(debug_mode_loc.as_ref(), DEBUG_MODE);
|
||||
|
||||
|
@ -703,7 +722,7 @@ pub fn Display() -> View {
|
|||
// bind them to the corresponding attributes in the vertex
|
||||
// shader
|
||||
bind_new_buffer_to_attribute(&ctx, point_position_attr, SPACE_DIM as i32, point_positions.as_slice());
|
||||
bind_new_buffer_to_attribute(&ctx, point_color_attr, COLOR_SIZE as i32, scene.points.colors.concat().as_slice());
|
||||
bind_new_buffer_to_attribute(&ctx, point_color_attr, (COLOR_SIZE + 1) as i32, scene.points.colors_with_opacity.concat().as_slice());
|
||||
bind_new_buffer_to_attribute(&ctx, point_highlight_attr, 1 as i32, scene.points.highlights.as_slice());
|
||||
bind_new_buffer_to_attribute(&ctx, point_selection_attr, 1 as i32, scene.points.selections.as_slice());
|
||||
|
||||
|
@ -851,7 +870,11 @@ pub fn Display() -> View {
|
|||
let (dir, pixel_size) = event_dir(&event);
|
||||
console::log_1(&JsValue::from(dir.to_string()));
|
||||
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)) {
|
||||
Some(depth) => match clicked {
|
||||
Some((_, best_depth)) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue