updated packages
This commit is contained in:
29
Cargo.toml
Normal file
29
Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
name = "protostar"
|
||||||
|
version = "0.4.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.1.3", features = ["derive"] }
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
directories = "4.0.1"
|
||||||
|
dirs = "4.0.0"
|
||||||
|
ez-pixmap = "0.2.2"
|
||||||
|
glam = { version = "0.22.0", features = ["mint"] }
|
||||||
|
image = "0.24.5"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
manifest-dir-macros = "0.1.16"
|
||||||
|
mint = "0.5.9"
|
||||||
|
nix = "0.26.1"
|
||||||
|
resvg = "0.29.0"
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
|
stardust-xr-fusion = "0.38.0"
|
||||||
|
stardust-xr-molecules = "0.21.0"
|
||||||
|
tokio = { version = "1.24.1", features = ["full"] }
|
||||||
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
tween = "2.0.0"
|
||||||
|
ustr = "0.9.0"
|
||||||
|
walkdir = "2.3.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempdir = "0.3.7"
|
||||||
162
src/protostar.rs
Normal file
162
src/protostar.rs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
use crate::xdg::{DesktopFile, Icon, RawIconType};
|
||||||
|
use color_eyre::eyre::{eyre, Result};
|
||||||
|
use glam::Quat;
|
||||||
|
use mint::Vector3;
|
||||||
|
use nix::unistd::{execv, fork};
|
||||||
|
use stardust_xr_fusion::{
|
||||||
|
client::{Client, FrameInfo, RootHandler},
|
||||||
|
core::values::Transform,
|
||||||
|
drawable::{MaterialParameter, Model, ResourceID},
|
||||||
|
fields::BoxField,
|
||||||
|
node::NodeType,
|
||||||
|
spatial::Spatial,
|
||||||
|
startup_settings::StartupSettings,
|
||||||
|
};
|
||||||
|
use stardust_xr_molecules::{GrabData, Grabbable};
|
||||||
|
use std::{f32::consts::PI, ffi::CStr, sync::Arc};
|
||||||
|
use tween::{QuartInOut, Tweener};
|
||||||
|
use ustr::ustr;
|
||||||
|
|
||||||
|
fn model_from_icon(parent: &Spatial, icon: &Icon) -> Result<Model> {
|
||||||
|
let model = match icon {
|
||||||
|
Icon::Png(path) => {
|
||||||
|
let model = Model::create(
|
||||||
|
parent,
|
||||||
|
Transform::from_rotation(Quat::from_rotation_y(PI)),
|
||||||
|
&ResourceID::new_namespaced("protostar", "cartridge"),
|
||||||
|
)?;
|
||||||
|
model.set_material_parameter(
|
||||||
|
0,
|
||||||
|
"diffuse",
|
||||||
|
MaterialParameter::Texture(ResourceID::Direct(path.clone())),
|
||||||
|
)?;
|
||||||
|
model
|
||||||
|
}
|
||||||
|
Icon::Gltf(path) => Model::create(
|
||||||
|
parent,
|
||||||
|
Transform::from_scale([0.05; 3]),
|
||||||
|
&ResourceID::new_direct(path)?,
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
Ok(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProtoStar {
|
||||||
|
client: Arc<Client>,
|
||||||
|
grabbable: Grabbable,
|
||||||
|
field: BoxField,
|
||||||
|
icon: Model,
|
||||||
|
icon_shrink: Option<Tweener<f32, f64, QuartInOut>>,
|
||||||
|
execute_command: String,
|
||||||
|
}
|
||||||
|
impl ProtoStar {
|
||||||
|
pub fn create_from_desktop_file(parent: &Spatial, desktop_file: DesktopFile) -> Result<Self> {
|
||||||
|
// dbg!(&desktop_file);
|
||||||
|
let mut raw_icons = desktop_file.get_raw_icons();
|
||||||
|
let last_icon = raw_icons.pop();
|
||||||
|
let icon = raw_icons
|
||||||
|
.into_iter()
|
||||||
|
.find(|i| match i {
|
||||||
|
RawIconType::Png(_) => false,
|
||||||
|
RawIconType::Svg(_) => false,
|
||||||
|
RawIconType::Gltf(_) => true,
|
||||||
|
})
|
||||||
|
.or(last_icon)
|
||||||
|
.map(|i| dbg!(i.process(64)).ok())
|
||||||
|
.ok_or_else(|| eyre!("No compatible icons found"))?;
|
||||||
|
Self::new_raw(
|
||||||
|
parent,
|
||||||
|
icon,
|
||||||
|
desktop_file.command.ok_or_else(|| eyre!("No command"))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn new_raw(parent: &Spatial, icon: Option<Icon>, execute_command: String) -> Result<Self> {
|
||||||
|
let field = BoxField::create(
|
||||||
|
parent,
|
||||||
|
Transform::default(),
|
||||||
|
match icon.as_ref() {
|
||||||
|
Some(Icon::Png(_)) => [0.05, 0.0665, 0.005],
|
||||||
|
_ => [0.05; 3],
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let grabbable = Grabbable::new(
|
||||||
|
parent,
|
||||||
|
Transform::default(),
|
||||||
|
&field,
|
||||||
|
GrabData {
|
||||||
|
max_distance: 0.025,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
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_scale([0.05; 3]),
|
||||||
|
&ResourceID::new_namespaced("protostar", "default_icon"),
|
||||||
|
)?)
|
||||||
|
})?;
|
||||||
|
Ok(ProtoStar {
|
||||||
|
client: parent.client()?,
|
||||||
|
grabbable,
|
||||||
|
field,
|
||||||
|
icon,
|
||||||
|
icon_shrink: None,
|
||||||
|
execute_command,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn content_parent(&self) -> &Spatial {
|
||||||
|
self.grabbable.content_parent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl RootHandler for ProtoStar {
|
||||||
|
fn frame(&mut self, info: FrameInfo) {
|
||||||
|
self.grabbable.update(&info);
|
||||||
|
|
||||||
|
if let Some(icon_shrink) = &mut self.icon_shrink {
|
||||||
|
if !icon_shrink.is_finished() {
|
||||||
|
let scale = icon_shrink.move_by(info.delta);
|
||||||
|
self.icon
|
||||||
|
.set_scale(None, Vector3::from([scale; 3]))
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
self.client.stop_loop();
|
||||||
|
}
|
||||||
|
} else if self.grabbable.grab_action().actor_stopped() {
|
||||||
|
let startup_settings = StartupSettings::create(&self.field.client().unwrap()).unwrap();
|
||||||
|
self.icon
|
||||||
|
.set_spatial_parent_in_place(self.client.get_root())
|
||||||
|
.unwrap();
|
||||||
|
self.grabbable
|
||||||
|
.content_parent()
|
||||||
|
.set_rotation(
|
||||||
|
Some(&self.field.client().unwrap().get_root()),
|
||||||
|
Quat::IDENTITY,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
startup_settings
|
||||||
|
.set_root(self.grabbable.content_parent())
|
||||||
|
.unwrap();
|
||||||
|
self.icon_shrink = Some(Tweener::quart_in_out(1.0, 0.0, 0.25));
|
||||||
|
let future = startup_settings.generate_startup_token().unwrap();
|
||||||
|
let executable = dbg!(self.execute_command.clone());
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
std::env::set_var("STARDUST_STARTUP_TOKEN", future.await.unwrap());
|
||||||
|
if unsafe { fork() }.unwrap().is_parent() {
|
||||||
|
println!("Launching \"{}\"...", &executable);
|
||||||
|
execv::<&CStr>(
|
||||||
|
ustr("/bin/sh").as_cstr(),
|
||||||
|
&[
|
||||||
|
ustr("/bin/sh").as_cstr(),
|
||||||
|
ustr("-c").as_cstr(),
|
||||||
|
ustr(&executable).as_cstr(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user