diff --git a/Cargo.lock b/Cargo.lock index 56eed92..ba21c5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,7 @@ version = "0.1.0" dependencies = [ "clap", "color-eyre", + "color-rs", "glam", "manifest-dir-macros", "mint", @@ -702,7 +703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e31b487427ff5df1386fa4721fcf41923140eb72fc20d776ac95ccbc21fa7bbb" dependencies = [ "dirs 4.0.0", - "itertools", + "itertools 0.11.0", "once_cell", "rust-ini 0.18.0", "thiserror", @@ -849,6 +850,7 @@ version = "0.1.0" dependencies = [ "clap", "color-eyre", + "color-rs", "glam", "manifest-dir-macros", "mint", @@ -960,6 +962,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -1337,7 +1348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cad0c4b129e9696e37cb712b243777b90ef489a0bfaa0ac34e7d9b860e4f134" dependencies = [ "heck", - "itertools", + "itertools 0.11.0", "proc-macro-error", "proc-macro2", "quote", @@ -1516,7 +1527,7 @@ dependencies = [ "freedesktop-icons-greedy", "glam", "image", - "itertools", + "itertools 0.12.0", "lazy_static", "linicon-theme", "manifest-dir-macros", @@ -1920,9 +1931,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" dependencies = [ "base64", "chrono", @@ -1937,9 +1948,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ "darling", "proc-macro2", @@ -1986,6 +1997,7 @@ version = "0.1.0" dependencies = [ "clap", "color-eyre", + "color-rs", "glam", "manifest-dir-macros", "mint", @@ -2009,6 +2021,7 @@ version = "0.1.0" dependencies = [ "clap", "color-eyre", + "color-rs", "glam", "manifest-dir-macros", "mint", @@ -2049,7 +2062,7 @@ dependencies = [ [[package]] name = "stardust-xr" version = "0.14.1" -source = "git+https://github.com/StardustXR/core.git#7b6c7b1b77075a7035f8a3ef07b430863ed9d60e" +source = "git+https://github.com/StardustXR/core.git#975331f9739a9f6cb90ec75813b7720c86225848" dependencies = [ "cluFlock", "color-rs", @@ -2069,7 +2082,7 @@ dependencies = [ [[package]] name = "stardust-xr-fusion" version = "0.43.2" -source = "git+https://github.com/StardustXR/core.git#7b6c7b1b77075a7035f8a3ef07b430863ed9d60e" +source = "git+https://github.com/StardustXR/core.git#975331f9739a9f6cb90ec75813b7720c86225848" dependencies = [ "color-eyre", "color-rs", @@ -2081,6 +2094,7 @@ dependencies = [ "rustc-hash", "serde", "serde_repr", + "serde_with", "stardust-xr", "thiserror", "tokio", @@ -2090,7 +2104,7 @@ dependencies = [ [[package]] name = "stardust-xr-molecules" version = "0.29.0" -source = "git+https://github.com/StardustXR/molecules.git#6e389f837375a34a10dfd35a633072a77a9f14d8" +source = "git+https://github.com/StardustXR/molecules.git#2e60ed7f75a1a79d89b83237dea4d208bc1ab01c" dependencies = [ "color-rs", "glam", @@ -2109,7 +2123,7 @@ dependencies = [ [[package]] name = "stardust-xr-schemas" version = "1.5.3" -source = "git+https://github.com/StardustXR/core.git#7b6c7b1b77075a7035f8a3ef07b430863ed9d60e" +source = "git+https://github.com/StardustXR/core.git#975331f9739a9f6cb90ec75813b7720c86225848" dependencies = [ "flatbuffers", "flexbuffers", diff --git a/app_grid/Cargo.toml b/app_grid/Cargo.toml index de34f34..74b6129 100644 --- a/app_grid/Cargo.toml +++ b/app_grid/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" tokio = { version = "1.32.0", features = ["rt", "tokio-macros", "sync"] } protostar = { path = "../protostar" } color-eyre = "0.6.2" +color-rs = "0.8.0" clap = "4.4.6" manifest-dir-macros = "0.1.18" glam = "0.24.2" diff --git a/app_grid/src/main.rs b/app_grid/src/main.rs index b91d3d4..fa13191 100644 --- a/app_grid/src/main.rs +++ b/app_grid/src/main.rs @@ -1,3 +1,4 @@ +use color::rgba_linear; use color_eyre::eyre::Result; use glam::{Quat, Vec3}; use manifest_dir_macros::directory_relative_path; @@ -93,9 +94,10 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { Transform::from_rotation(Quat::from_rotation_y(PI)), &ResourceID::new_namespaced("protostar", "cartridge"), )?; - model - .model_part("Cartridge")? - .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; + model.model_part("Cartridge")?.set_material_parameter( + "color", + MaterialParameter::Color(rgba_linear!(0.0, 1.0, 1.0, 1.0)), + )?; model.model_part("Icon")?.set_material_parameter( "diffuse", MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), @@ -182,12 +184,12 @@ impl App { self.grabbable.content_parent() } - fn bring_back(&self) { - self.grabbable - .content_parent() - .set_transform(Some(&self.root), Transform::identity()) - .unwrap(); - } + // fn bring_back(&self) { + // self.grabbable + // .content_parent() + // .set_transform(Some(&self.root), Transform::identity()) + // .unwrap(); + // } fn frame(&mut self, info: FrameInfo) { let _ = self.grabbable.update(&info); @@ -196,23 +198,29 @@ impl App { self.grabbable.cancel_angular_velocity(); self.grabbable.cancel_linear_velocity(); - if !self.grabbable.valid() { - self.bring_back(); - return; - } - let Ok(distance_future) = self.grabbable + // if !self.grabbable.valid() { + // self.bring_back(); + // return; + // } + let Ok(distance_future) = self + .grabbable .content_parent() .get_position_rotation_scale(&self.root) - else {return}; + else { + return; + }; let application = self.application.clone(); let space = self.content_parent().alias(); let root = self.root.alias(); tokio::task::spawn(async move { - let Ok((distance, _rotation, _scale)) = distance_future.await else { space - .set_transform(Some(&root), Transform::identity()) - .unwrap(); return}; + let Ok((distance, _rotation, _scale)) = distance_future.await else { + space + .set_transform(Some(&root), Transform::identity()) + .unwrap(); + return; + }; let distance = Vec3::from(distance).length_squared(); if distance > ACTIVATION_DISTANCE.powi(2) { diff --git a/assets/cartridge.blend b/assets/cartridge.blend index 245b616..1b6b50c 100644 Binary files a/assets/cartridge.blend and b/assets/cartridge.blend differ diff --git a/assets/hexagon.blend b/assets/hexagon.blend index 20cd188..21655d5 100644 Binary files a/assets/hexagon.blend and b/assets/hexagon.blend differ diff --git a/hexagon_launcher/Cargo.toml b/hexagon_launcher/Cargo.toml index 767428b..4f2ce39 100644 --- a/hexagon_launcher/Cargo.toml +++ b/hexagon_launcher/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] tokio = { version = "1.32.0", features = ["rt", "tokio-macros", "sync"] } protostar = { path = "../protostar" } +color-rs = "0.8.0" color-eyre = "0.6.2" clap = "4.4.6" manifest-dir-macros = "0.1.18" diff --git a/hexagon_launcher/res/protostar/hexagon/hex_atlas.png b/hexagon_launcher/res/protostar/hexagon/hex_atlas.png index 5376c46..03e4f18 100644 Binary files a/hexagon_launcher/res/protostar/hexagon/hex_atlas.png and b/hexagon_launcher/res/protostar/hexagon/hex_atlas.png differ diff --git a/hexagon_launcher/res/protostar/hexagon/hexagon.bin b/hexagon_launcher/res/protostar/hexagon/hexagon.bin index f56fec4..b40c29c 100644 Binary files a/hexagon_launcher/res/protostar/hexagon/hexagon.bin and b/hexagon_launcher/res/protostar/hexagon/hexagon.bin differ diff --git a/hexagon_launcher/res/protostar/hexagon/hexagon.gltf b/hexagon_launcher/res/protostar/hexagon/hexagon.gltf index f0480e3..21049a7 100644 --- a/hexagon_launcher/res/protostar/hexagon/hexagon.gltf +++ b/hexagon_launcher/res/protostar/hexagon/hexagon.gltf @@ -1,6 +1,6 @@ { "asset":{ - "generator":"Khronos glTF Blender I/O v3.5.30", + "generator":"Khronos glTF Blender I/O v3.6.6", "version":"2.0" }, "extensionsUsed":[ @@ -51,9 +51,9 @@ "name":"Hex", "pbrMetallicRoughness":{ "baseColorFactor":[ - 1, - 0, - 0, + 0.9720873236656189, + 0.018567396327853203, + 0.017742767930030823, 1 ], "baseColorTexture":{ @@ -173,14 +173,14 @@ "componentType":5126, "count":54, "max":[ - 1.0441828966140747, - 0.05000000074505806, - 0.9042890667915344 + 1.0166369676589966, + 0.021040409803390503, + 0.8804334998130798 ], "min":[ - -1.0441828966140747, - 0, - -0.9042890667915344 + -1.0166369676589966, + -7.071532309055328e-06, + -0.8804334998130798 ], "type":"VEC3" }, diff --git a/hexagon_launcher/src/app.rs b/hexagon_launcher/src/app.rs new file mode 100644 index 0000000..4e3c24a --- /dev/null +++ b/hexagon_launcher/src/app.rs @@ -0,0 +1,256 @@ +use color_eyre::eyre::Result; +use glam::{EulerRot, Quat, Vec3}; +use mint::Vector3; +use protostar::{ + application::Application, + xdg::{DesktopFile, Icon, IconType}, +}; +use stardust_xr_fusion::{ + client::FrameInfo, + core::values::Transform, + drawable::{Alignment, Bounds, MaterialParameter, Model, ResourceID, Text, TextFit, TextStyle}, + fields::BoxField, + node::NodeType, + spatial::Spatial, +}; +use stardust_xr_molecules::{Grabbable, GrabbableSettings}; +use std::f32::consts::PI; +use tween::{QuartInOut, Tweener}; + +use crate::{ACTIVATION_DISTANCE, APP_SIZE, DEFAULT_HEX_COLOR}; + +// Model handling +fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { + match &icon.icon_type { + IconType::Png => { + let t = Transform::from_rotation_scale( + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + [APP_SIZE / 2.0; 3], + ); + + let model = Model::create( + parent, + t, + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), + )?; + model + .model_part("Hex")? + .set_material_parameter("color", MaterialParameter::Color(DEFAULT_HEX_COLOR))?; + model.model_part("Icon")?.set_material_parameter( + "diffuse", + MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), + )?; + Ok(model) + } + IconType::Gltf => Ok(Model::create( + parent, + Transform::from_scale([0.05; 3]), + &ResourceID::new_direct(icon.path.clone())?, + )?), + _ => panic!("Invalid Icon Type"), + } +} + +pub struct App { + application: Application, + parent: Spatial, + position: Vector3, + grabbable: Grabbable, + _field: BoxField, + icon: Model, + label: Option, + grabbable_shrink: Option>, + grabbable_grow: Option>, + grabbable_move: Option>, + currently_shown: bool, +} +impl App { + pub fn create_from_desktop_file( + parent: &Spatial, + position: impl Into>, + desktop_file: DesktopFile, + ) -> Result { + let position = position.into(); + let field = BoxField::create(parent, Transform::default(), [APP_SIZE; 3])?; + let application = Application::create(desktop_file)?; + let icon = application.icon(128, false); + let grabbable = Grabbable::create( + parent, + Transform::from_position(position), + &field, + GrabbableSettings { + max_distance: 0.01, + ..Default::default() + }, + )?; + grabbable.content_parent().set_spatial_parent(parent)?; + field.set_spatial_parent(grabbable.content_parent())?; + let icon = icon + .map(|i| model_from_icon(grabbable.content_parent(), &i)) + .unwrap_or_else(|| { + Ok(Model::create( + grabbable.content_parent(), + Transform::from_rotation_scale( + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + [APP_SIZE * 0.5; 3], + ), + &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), + )?) + })?; + + let label_style = TextStyle { + character_height: APP_SIZE * 2.0, + bounds: Some(Bounds { + bounds: [1.0; 2].into(), + fit: TextFit::Wrap, + bounds_align: Alignment::XCenter | Alignment::YCenter, + }), + text_align: Alignment::Center.into(), + ..Default::default() + }; + let label = application.name().and_then(|name| { + Text::create( + &icon, + Transform::from_position_rotation( + [0.0, 0.1, -(APP_SIZE * 4.0)], + Quat::from_rotation_x(PI * 0.5), + ), + name, + label_style, + ) + .ok() + }); + Ok(App { + parent: parent.alias(), + position, + grabbable, + _field: field, + label, + application, + icon, + grabbable_shrink: None, + grabbable_grow: None, + grabbable_move: None, + currently_shown: true, + }) + } + pub fn content_parent(&self) -> &Spatial { + self.grabbable.content_parent() + } + pub fn toggle(&mut self) { + self.grabbable.set_enabled(!self.currently_shown).unwrap(); + if self.currently_shown { + self.grabbable_move = Some(Tweener::quart_in_out(1.0, 0.0001, 0.25)); //TODO make the scale a parameter + } else { + self.icon.set_enabled(true).unwrap(); + if let Some(label) = self.label.as_ref() { + label.set_enabled(true).unwrap() + } + self.grabbable_move = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); + } + self.currently_shown = !self.currently_shown; + } + + pub fn frame(&mut self, info: FrameInfo) { + let _ = self.grabbable.update(&info); + + if let Some(grabbable_move) = &mut self.grabbable_move { + if !grabbable_move.is_finished() { + let scale = grabbable_move.move_by(info.delta); + self.grabbable + .content_parent() + .set_position(Some(&self.parent), Vec3::from(self.position) * scale) + .unwrap(); + } else { + if grabbable_move.final_value() == 0.0001 { + self.icon.set_enabled(false).unwrap(); + if let Some(label) = self.label.as_ref() { + label.set_enabled(false).unwrap() + } + } + self.grabbable_move = None; + } + } + if let Some(grabbable_shrink) = &mut self.grabbable_shrink { + if !grabbable_shrink.is_finished() { + let scale = grabbable_shrink.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + if self.currently_shown { + self.grabbable_grow = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); + self.grabbable.cancel_angular_velocity(); + self.grabbable.cancel_linear_velocity(); + } + self.grabbable_shrink = None; + self.grabbable + .content_parent() + .set_position(Some(&self.parent), self.position) + .unwrap(); + self.grabbable + .content_parent() + .set_rotation(Some(&self.parent), Quat::default()) + .unwrap(); + self.icon + .set_rotation( + None, + Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), + ) + .unwrap(); + } + } else if let Some(grabbable_grow) = &mut self.grabbable_grow { + if !grabbable_grow.is_finished() { + let scale = grabbable_grow.move_by(info.delta); + self.grabbable + .content_parent() + .set_scale(Some(&self.parent), Vector3::from([scale; 3])) + .unwrap(); + } else { + self.grabbable + .content_parent() + .set_spatial_parent(&self.parent) + .unwrap(); + self.grabbable_grow = None; + } + } else if self.grabbable.grab_action().actor_stopped() { + self.grabbable_shrink = Some(Tweener::quart_in_out(APP_SIZE * 0.5, 0.0001, 0.25)); + let Ok(distance_future) = self + .grabbable + .content_parent() + .get_position_rotation_scale(&self.parent) + else { + return; + }; + + let application = self.application.clone(); + let space = self.content_parent().alias(); + + //TODO: split the executable string for the args + tokio::task::spawn(async move { + let distance_vector = distance_future.await.ok().unwrap().0; + let distance = Vec3::from(distance_vector).length_squared(); + + if distance > ACTIVATION_DISTANCE { + let client = space.node().client().unwrap(); + let (_, space_rot, _) = space + .get_position_rotation_scale(&client.get_root()) + .unwrap() + .await + .unwrap(); + let (_, y_rot, _) = Quat::from(space_rot).to_euler(EulerRot::XYZ); + let _ = space.set_transform( + Some(client.get_root()), + Transform::from_rotation_scale(Quat::from_rotation_y(y_rot), [1.0; 3]), + ); + let _ = application.launch(&space); + } + }); + } + } +} diff --git a/hexagon_launcher/src/main.rs b/hexagon_launcher/src/main.rs index e2a8ead..1858f49 100644 --- a/hexagon_launcher/src/main.rs +++ b/hexagon_launcher/src/main.rs @@ -1,35 +1,31 @@ +pub mod app; pub mod hex; +use app::App; +use color::{color_space::LinearRgb, rgba_linear, Rgba}; use color_eyre::eyre::Result; -use glam::{EulerRot, Quat, Vec3}; +use glam::Quat; use hex::{HEX_CENTER, HEX_DIRECTION_VECTORS}; use manifest_dir_macros::directory_relative_path; -use mint::Vector3; -use protostar::{ - application::Application, - xdg::{get_desktop_files, parse_desktop_file, DesktopFile, Icon, IconType}, -}; +use protostar::xdg::{get_desktop_files, parse_desktop_file, DesktopFile}; use stardust_xr_fusion::{ client::{Client, ClientState, FrameInfo, RootHandler}, core::values::Transform, - drawable::{Alignment, Bounds, MaterialParameter, Model, ResourceID, Text, TextFit, TextStyle}, + drawable::{MaterialParameter, Model, ResourceID}, fields::BoxField, node::NodeError, - node::NodeType, - spatial::Spatial, }; -use stardust_xr_molecules::{touch_plane::TouchPlane, Grabbable, GrabbableSettings}; +use stardust_xr_molecules::{touch_plane::TouchPlane, Grabbable, GrabbableSettings, PointerMode}; use std::f32::consts::PI; -use tween::{QuartInOut, Tweener}; const APP_SIZE: f32 = 0.06; const PADDING: f32 = 0.005; const MODEL_SCALE: f32 = 0.03; const ACTIVATION_DISTANCE: f32 = 0.05; -const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0]; -const BTN_SELECTED_COLOR: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; -const BTN_COLOR: [f32; 4] = [1.0, 1.0, 0.0, 1.0]; +const DEFAULT_HEX_COLOR: Rgba = rgba_linear!(0.211, 0.937, 0.588, 1.0); +const BTN_SELECTED_COLOR: Rgba = rgba_linear!(0.0, 1.0, 0.0, 1.0); +const BTN_COLOR: Rgba = rgba_linear!(1.0, 1.0, 0.0, 1.0); #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { @@ -137,6 +133,8 @@ impl Button { &field, GrabbableSettings { max_distance: 0.01, + pointer_mode: PointerMode::Align, + magnet: false, ..Default::default() }, )?; @@ -179,236 +177,3 @@ impl Button { self.touch_plane.update(); } } - -// Model handling -fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { - match &icon.icon_type { - IconType::Png => { - let t = Transform::from_rotation_scale( - Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), - [APP_SIZE / 2.0; 3], - ); - - let model = Model::create( - parent, - t, - &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), - )?; - model - .model_part("Hex")? - .set_material_parameter("color", MaterialParameter::Color(CYAN))?; - model.model_part("Icon")?.set_material_parameter( - "diffuse", - MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), - )?; - Ok(model) - } - IconType::Gltf => Ok(Model::create( - parent, - Transform::from_scale([0.05; 3]), - &ResourceID::new_direct(icon.path.clone())?, - )?), - _ => panic!("Invalid Icon Type"), - } -} - -pub struct App { - application: Application, - parent: Spatial, - position: Vector3, - grabbable: Grabbable, - _field: BoxField, - icon: Model, - label: Option, - grabbable_shrink: Option>, - grabbable_grow: Option>, - grabbable_move: Option>, - currently_shown: bool, -} -impl App { - pub fn create_from_desktop_file( - parent: &Spatial, - position: impl Into>, - desktop_file: DesktopFile, - ) -> Result { - let position = position.into(); - let field = BoxField::create(parent, Transform::default(), [APP_SIZE; 3])?; - let application = Application::create(desktop_file)?; - let icon = application.icon(128, false); - let grabbable = Grabbable::create( - parent, - Transform::from_position(position), - &field, - GrabbableSettings { - max_distance: 0.01, - ..Default::default() - }, - )?; - grabbable.content_parent().set_spatial_parent(parent)?; - field.set_spatial_parent(grabbable.content_parent())?; - let icon = icon - .map(|i| model_from_icon(grabbable.content_parent(), &i)) - .unwrap_or_else(|| { - Ok(Model::create( - grabbable.content_parent(), - Transform::from_rotation_scale( - Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), - [APP_SIZE * 0.5; 3], - ), - &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), - )?) - })?; - - let label_style = TextStyle { - character_height: APP_SIZE * 2.0, - bounds: Some(Bounds { - bounds: [1.0; 2].into(), - fit: TextFit::Wrap, - bounds_align: Alignment::XCenter | Alignment::YCenter, - }), - text_align: Alignment::Center.into(), - ..Default::default() - }; - let label = application.name().and_then(|name| { - Text::create( - &icon, - Transform::from_position_rotation( - [0.0, 0.1, -(APP_SIZE * 4.0)], - Quat::from_rotation_x(PI * 0.5), - ), - name, - label_style, - ) - .ok() - }); - Ok(App { - parent: parent.alias(), - position, - grabbable, - _field: field, - label, - application, - icon, - grabbable_shrink: None, - grabbable_grow: None, - grabbable_move: None, - currently_shown: true, - }) - } - pub fn content_parent(&self) -> &Spatial { - self.grabbable.content_parent() - } - pub fn toggle(&mut self) { - self.grabbable.set_enabled(!self.currently_shown).unwrap(); - if self.currently_shown { - self.grabbable_move = Some(Tweener::quart_in_out(1.0, 0.0001, 0.25)); //TODO make the scale a parameter - } else { - self.icon.set_enabled(true).unwrap(); - if let Some(label) = self.label.as_ref() { - label.set_enabled(true).unwrap() - } - self.grabbable_move = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); - } - self.currently_shown = !self.currently_shown; - } - - fn frame(&mut self, info: FrameInfo) { - let _ = self.grabbable.update(&info); - - if let Some(grabbable_move) = &mut self.grabbable_move { - if !grabbable_move.is_finished() { - let scale = grabbable_move.move_by(info.delta); - self.grabbable - .content_parent() - .set_position(Some(&self.parent), Vec3::from(self.position) * scale) - .unwrap(); - } else { - if grabbable_move.final_value() == 0.0001 { - self.icon.set_enabled(false).unwrap(); - if let Some(label) = self.label.as_ref() { - label.set_enabled(false).unwrap() - } - } - self.grabbable_move = None; - } - } - if let Some(grabbable_shrink) = &mut self.grabbable_shrink { - if !grabbable_shrink.is_finished() { - let scale = grabbable_shrink.move_by(info.delta); - self.grabbable - .content_parent() - .set_scale(Some(&self.parent), Vector3::from([scale; 3])) - .unwrap(); - } else { - self.grabbable - .content_parent() - .set_spatial_parent(&self.parent) - .unwrap(); - if self.currently_shown { - self.grabbable_grow = Some(Tweener::quart_in_out(0.0001, 1.0, 0.25)); - self.grabbable.cancel_angular_velocity(); - self.grabbable.cancel_linear_velocity(); - } - self.grabbable_shrink = None; - self.grabbable - .content_parent() - .set_position(Some(&self.parent), self.position) - .unwrap(); - self.grabbable - .content_parent() - .set_rotation(Some(&self.parent), Quat::default()) - .unwrap(); - self.icon - .set_rotation( - None, - Quat::from_rotation_x(PI / 2.0) * Quat::from_rotation_y(PI), - ) - .unwrap(); - } - } else if let Some(grabbable_grow) = &mut self.grabbable_grow { - if !grabbable_grow.is_finished() { - let scale = grabbable_grow.move_by(info.delta); - self.grabbable - .content_parent() - .set_scale(Some(&self.parent), Vector3::from([scale; 3])) - .unwrap(); - } else { - self.grabbable - .content_parent() - .set_spatial_parent(&self.parent) - .unwrap(); - self.grabbable_grow = None; - } - } else if self.grabbable.valid() && self.grabbable.grab_action().actor_stopped() { - self.grabbable_shrink = Some(Tweener::quart_in_out(APP_SIZE * 0.5, 0.0001, 0.25)); - let Ok(distance_future) = self.grabbable - .content_parent() - .get_position_rotation_scale(&self.parent) - else {return}; - - let application = self.application.clone(); - let space = self.content_parent().alias(); - - //TODO: split the executable string for the args - tokio::task::spawn(async move { - let distance_vector = distance_future.await.ok().unwrap().0; - let distance = Vec3::from(distance_vector).length_squared(); - - if distance > ACTIVATION_DISTANCE { - let client = space.node().client().unwrap(); - let (_, space_rot, _) = space - .get_position_rotation_scale(&client.get_root()) - .unwrap() - .await - .unwrap(); - let (_, y_rot, _) = Quat::from(space_rot).to_euler(EulerRot::XYZ); - let _ = space.set_transform( - Some(client.get_root()), - Transform::from_rotation_scale(Quat::from_rotation_y(y_rot), [1.0; 3]), - ); - let _ = application.launch(&space); - } - }); - } - } -} diff --git a/protostar/Cargo.toml b/protostar/Cargo.toml index 493dc0c..37af4dc 100644 --- a/protostar/Cargo.toml +++ b/protostar/Cargo.toml @@ -12,7 +12,7 @@ ez-pixmap = "0.2.2" freedesktop-icons-greedy = "0.2.6" glam = { version = "0.24.0", features = ["mint"] } image = "0.24.5" -itertools = "0.11.0" +itertools = "0.12.0" lazy_static = "1.4.0" linicon-theme = "1.2.0" manifest-dir-macros = "0.1.16" @@ -22,7 +22,7 @@ regex = "1.7.1" resvg = "0.29.0" rustc-hash = "1.1.0" serde = "1.0.155" -serde_with = "3.3.0" +serde_with = "3.4.0" tokio = { version = "1.24.1", features = ["full"] } toml = "0.8.2" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/single/Cargo.toml b/single/Cargo.toml index facb36f..cd30684 100644 --- a/single/Cargo.toml +++ b/single/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" tokio = { version = "1.32.0", features = ["rt", "tokio-macros", "sync"] } protostar = { path = "../protostar" } color-eyre = "0.6.2" +color-rs = "0.8.0" clap = "4.4.6" manifest-dir-macros = "0.1.18" glam = "0.24.2" diff --git a/single/src/single.rs b/single/src/single.rs index bea6795..dfe5a34 100644 --- a/single/src/single.rs +++ b/single/src/single.rs @@ -1,3 +1,4 @@ +use color::rgba_linear; use color_eyre::eyre::Result; use glam::{Quat, Vec3}; use mint::Vector3; @@ -33,9 +34,10 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { t, &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), )?; - model - .model_part("Hex")? - .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; + model.model_part("Hex")?.set_material_parameter( + "color", + MaterialParameter::Color(rgba_linear!(0.0, 1.0, 1.0, 1.0)), + )?; model.model_part("Icon")?.set_material_parameter( "diffuse", MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), @@ -211,12 +213,15 @@ impl RootHandler for Single { .unwrap(); self.grabbable_grow = None; } - } else if self.grabbable.valid() && self.grabbable.grab_action().actor_stopped() { + } else if self.grabbable.grab_action().actor_stopped() { self.grabbable_shrink = Some(Tweener::quart_in_out(MODEL_SCALE, 0.0001, 0.25)); - let Ok(distance_future) = self.grabbable + let Ok(distance_future) = self + .grabbable .content_parent() .get_position_rotation_scale(&self.parent) - else {return}; + else { + return; + }; let application = self.application.clone(); let space = self.content_parent().alias(); diff --git a/sirius/Cargo.toml b/sirius/Cargo.toml index 831e652..8149ffc 100644 --- a/sirius/Cargo.toml +++ b/sirius/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" tokio = { version = "1.32.0", features = ["rt", "tokio-macros", "sync"] } protostar = { path = "../protostar" } color-eyre = "0.6.2" +color-rs = "0.8.0" clap = "4.4.6" manifest-dir-macros = "0.1.18" glam = "0.24.2" diff --git a/sirius/src/main.rs b/sirius/src/main.rs index 3c8e163..8d52272 100644 --- a/sirius/src/main.rs +++ b/sirius/src/main.rs @@ -1,4 +1,5 @@ use clap::{self, Parser}; +use color::rgba_linear; use color_eyre::eyre::Result; use glam::{Quat, Vec3}; use manifest_dir_macros::directory_relative_path; @@ -164,36 +165,40 @@ impl RootHandler for Sirius { } } } - let color = [0.0, 1.0, 0.0, 1.0]; self.model .model_part("?????") .unwrap() - .set_material_parameter("color", MaterialParameter::Color(color)) + .set_material_parameter( + "color", + MaterialParameter::Color(rgba_linear!(0.0, 1.0, 0.0, 1.0)), + ) .unwrap(); self.model .model_part("?????") .unwrap() .set_material_parameter( "emission_factor", - MaterialParameter::Color(color.map(|c| c * 0.75)), + MaterialParameter::Color(rgba_linear!(0.0, 0.75, 0.0, 0.75)), ) .unwrap(); } if self.touch_plane.touch_stopped() { println!("Touch ended"); - let color = [1.0, 0.0, 0.0, 1.0]; self.model .model_part("?????") .unwrap() - .set_material_parameter("color", MaterialParameter::Color(color)) + .set_material_parameter( + "color", + MaterialParameter::Color(rgba_linear!(1.0, 0.0, 0.0, 1.0)), + ) .unwrap(); self.model .model_part("?????") .unwrap() .set_material_parameter( "emission_factor", - MaterialParameter::Color(color.map(|c| c * 0.5)), + MaterialParameter::Color(rgba_linear!(0.5, 0.0, 0.0, 0.5)), ) .unwrap(); } @@ -217,9 +222,10 @@ fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result { t, &ResourceID::new_namespaced("protostar", "hexagon/hexagon"), )?; - model - .model_part("Hex")? - .set_material_parameter("color", MaterialParameter::Color([0.0, 1.0, 1.0, 1.0]))?; + model.model_part("Hex")?.set_material_parameter( + "color", + MaterialParameter::Color(rgba_linear!(0.0, 1.0, 1.0, 1.0)), + )?; model.model_part("Icon")?.set_material_parameter( "diffuse", MaterialParameter::Texture(ResourceID::Direct(icon.path.clone())), @@ -402,12 +408,15 @@ impl App { .unwrap(); self.grabbable_grow = None; } - } else if self.grabbable.valid() && self.grabbable.grab_action().actor_stopped() { + } else if self.grabbable.grab_action().actor_stopped() { self.grabbable_shrink = Some(Tweener::quart_in_out(APP_SIZE * 0.5, 0.0001, 0.25)); - let Ok(distance_future) = self.grabbable + let Ok(distance_future) = self + .grabbable .content_parent() .get_position_rotation_scale(&self.parent) - else {return}; + else { + return; + }; let application = self.application.clone(); let space = self.content_parent().alias();