From 3493a798d10c1a7771362e0a49830a4c15f18e90 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Wed, 4 Sep 2024 16:27:28 -0700 Subject: [PATCH] Add low-curvature construction Also add infrastructure for switching between constructions. --- app-proto/inversive-display/main.css | 31 +++- app-proto/inversive-display/src/main.rs | 210 ++++++++++++++++++------ 2 files changed, 189 insertions(+), 52 deletions(-) diff --git a/app-proto/inversive-display/main.css b/app-proto/inversive-display/main.css index 7cdc831..7e8c710 100644 --- a/app-proto/inversive-display/main.css +++ b/app-proto/inversive-display/main.css @@ -18,14 +18,41 @@ canvas { margin-top: 5px; } -.control { +.hidden { + display: none; +} + +.control, .tab-pane { display: flex; flex-direction: row; width: 600px; } +input[type="radio"] { + display: none; +} + +.tab-pane > label { + border: 1px solid #aaa; + border-radius: 5px; + text-align: center; + padding: 5px; + margin-right: 10px; + margin-bottom: 5px; +} + +.tab-pane > label:has(:checked) { + border-color: #fcfcfc; + background-color: #555; +} + +.tab-pane > label:hover:not(:has(:checked)) { + border-color: #bbb; + background-color: #333; +} + label { - width: 150px; + width: 170px; } input { diff --git a/app-proto/inversive-display/src/main.rs b/app-proto/inversive-display/src/main.rs index 2042c08..1fbef8d 100644 --- a/app-proto/inversive-display/src/main.rs +++ b/app-proto/inversive-display/src/main.rs @@ -10,6 +10,7 @@ extern crate js_sys; use core::array; use nalgebra::{DMatrix, DVector}; +use std::f64::consts::FRAC_1_SQRT_2; use sycamore::{prelude::*, motion::create_raf, rt::{JsCast, JsValue}}; use web_sys::{console, window, WebGl2RenderingContext, WebGlProgram, WebGlShader, WebGlUniformLocation}; @@ -83,7 +84,7 @@ fn bind_vertex_attrib( ); } -fn push_gen_test_construction( +fn push_gen_construction( sphere_vec: &mut Vec>, construction_to_world: &DMatrix, ctrl_x: f64, @@ -99,17 +100,46 @@ fn push_gen_test_construction( sphere_vec.push(construction_to_world * engine::sphere(0.0, -0.15, -1.0, 0.25)); } +fn push_low_curv_construction( + sphere_vec: &mut Vec>, + construction_to_world: &DMatrix, + curv_x: f64, + curv_y: f64 +) { + sphere_vec.push(construction_to_world * DVector::from_column_slice(&[0.0, -1.0, 0.0, 0.5*curv_x, 0.0])); + sphere_vec.push(construction_to_world * DVector::from_column_slice(&[-FRAC_1_SQRT_2, 0.0, -FRAC_1_SQRT_2, 0.5*curv_y, 0.0])); + sphere_vec.push(construction_to_world * engine::sphere(0.5, 0.0, 0.5, FRAC_1_SQRT_2)); + sphere_vec.push(construction_to_world * engine::sphere(-0.5, 0.0, -0.5, FRAC_1_SQRT_2)); +} + +#[derive(Clone, Copy, PartialEq)] +enum Tab { + GenTab, + LowCurvTab +} + fn main() { // set up a config option that forwards panic messages to `console.error` #[cfg(feature = "console_error_panic_hook")] console_error_panic_hook::set_once(); sycamore::render(|| { - // controls + // tab selection + let tab_selection = create_signal(Tab::GenTab); + + // controls for general example + let gen_controls = create_node_ref(); let ctrl_x = create_signal(0.0); let ctrl_y = create_signal(0.0); let radius_x = create_signal(1.0); let radius_y = create_signal(1.0); + + // controls for low-curvature example + let low_curv_controls = create_node_ref(); + let curv_x = create_signal(0.0); + let curv_y = create_signal(0.0); + + // shared controls let opacity = create_signal(0.5); let highlight = create_signal(0.2); let turntable = create_signal(false); @@ -128,10 +158,20 @@ fn main() { // change listener let scene_changed = create_signal(true); create_effect(move || { + // track tab selection + tab_selection.track(); + + // track controls for general example ctrl_x.track(); ctrl_y.track(); radius_x.track(); radius_y.track(); + + // track controls for low-curvature example + curv_x.track(); + curv_y.track(); + + // track shared controls opacity.track(); highlight.track(); turntable.track(); @@ -142,6 +182,23 @@ fn main() { }); on_mount(move || { + // tab listener + create_effect(move || { + // get the control panel nodes + let gen_controls_node = gen_controls.get::(); + let low_curv_controls_node = low_curv_controls.get::(); + + // hide all the control panels + gen_controls_node.add_class("hidden"); + low_curv_controls_node.add_class("hidden"); + + // show the selected control panel + match tab_selection.get() { + Tab::GenTab => gen_controls_node.remove_class("hidden"), + Tab::LowCurvTab => low_curv_controls_node.remove_class("hidden") + } + }); + // list construction elements const SPHERE_MAX: usize = 200; let mut sphere_vec = Vec::>::new(); @@ -308,12 +365,19 @@ fn main() { // update the construction sphere_vec.clear(); - push_gen_test_construction( - &mut sphere_vec, - &construction_to_world, - ctrl_x.get(), ctrl_y.get(), - radius_x.get(), radius_y.get() - ); + match tab_selection.get() { + Tab::GenTab => push_gen_construction( + &mut sphere_vec, + &construction_to_world, + ctrl_x.get(), ctrl_y.get(), + radius_x.get(), radius_y.get() + ), + Tab::LowCurvTab => push_low_curv_construction( + &mut sphere_vec, + &construction_to_world, + curv_x.get(), curv_y.get() + ) + }; // set the resolution let width = canvas.width() as f32; @@ -362,51 +426,97 @@ fn main() { view! { div(id="app") { + div(class="tab-pane") { + label { + "General" + input( + type="radio", + name="tab", + prop:checked=tab_selection.get() == Tab::GenTab, + on:click=move |_| tab_selection.set(Tab::GenTab) + ) + } + label { + "Low curvature" + input( + type="radio", + name="tab", + prop:checked=tab_selection.get() == Tab::LowCurvTab, + on:change=move |_| tab_selection.set(Tab::LowCurvTab) + ) + } + } div { "Mean frame interval: " (mean_frame_interval.get()) " ms" } canvas(ref=display, width="600", height="600") - div(class="control") { - label(for="ctrl-x") { "Sphere 0 depth" } - input( - type="range", - id="ctrl-x", - min=-1.0, - max=1.0, - step=0.001, - bind:valueAsNumber=ctrl_x - ) + div(ref=gen_controls) { + div(class="control") { + label(for="ctrl-x") { "Sphere 0 depth" } + input( + type="range", + id="ctrl-x", + min=-1.0, + max=1.0, + step=0.001, + bind:valueAsNumber=ctrl_x + ) + } + div(class="control") { + label(for="ctrl-y") { "Sphere 1 depth" } + input( + type="range", + id="ctrl-y", + min=-1.0, + max=1.0, + step=0.001, + bind:valueAsNumber=ctrl_y + ) + } + div(class="control") { + label(for="radius-x") { "Sphere 0 radius" } + input( + type="range", + id="radius-x", + min=0.5, + max=1.5, + step=0.001, + bind:valueAsNumber=radius_x + ) + } + div(class="control") { + label(for="radius-y") { "Sphere 1 radius" } + input( + type="range", + id="radius-y", + min=0.5, + max=1.5, + step=0.001, + bind:valueAsNumber=radius_y + ) + } } - div(class="control") { - label(for="ctrl-y") { "Sphere 1 depth" } - input( - type="range", - id="ctrl-y", - min=-1.0, - max=1.0, - step=0.001, - bind:valueAsNumber=ctrl_y - ) - } - div(class="control") { - label(for="radius-x") { "Sphere 0 radius" } - input( - type="range", - id="radius-x", - min=0.5, - max=1.5, - step=0.001, - bind:valueAsNumber=radius_x - ) - } - div(class="control") { - label(for="radius-y") { "Sphere 1 radius" } - input( - type="range", - id="radius-y", - min=0.5, - max=1.5, - step=0.001, - bind:valueAsNumber=radius_y - ) + div(ref=low_curv_controls) { + div(class="control") { + label(for="curv-x") { "Sphere 0 curvature" } + input( + type="range", + id="curv-x", + min=0.0, + max=2.0, + step=0.001, + bind:valueAsNumber=curv_x + ) + } + div(class="control") { + label(for="curv-y") { "Sphere 1 curvature" } + input( + type="range", + id="curv-y", + min=0.0, + max=2.0, + step=0.001, + bind:valueAsNumber=curv_y + ) + } } div(class="control") { label(for="opacity") { "Opacity" }