feat: camera item
This commit is contained in:
@@ -5,6 +5,7 @@ mod objects;
|
|||||||
mod wayland;
|
mod wayland;
|
||||||
|
|
||||||
use crate::core::destroy_queue;
|
use crate::core::destroy_queue;
|
||||||
|
use crate::nodes::items::camera;
|
||||||
use crate::nodes::{audio, drawable, hmd, input};
|
use crate::nodes::{audio, drawable, hmd, input};
|
||||||
use crate::objects::input::eye_pointer::EyePointer;
|
use crate::objects::input::eye_pointer::EyePointer;
|
||||||
use crate::objects::input::mouse_pointer::MousePointer;
|
use crate::objects::input::mouse_pointer::MousePointer;
|
||||||
@@ -238,6 +239,7 @@ fn main() {
|
|||||||
let _span = _span.enter();
|
let _span = _span.enter();
|
||||||
|
|
||||||
hmd::frame(sk);
|
hmd::frame(sk);
|
||||||
|
camera::update(sk);
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
wayland.frame_event(sk);
|
wayland.frame_event(sk);
|
||||||
destroy_queue::clear();
|
destroy_queue::clear();
|
||||||
|
|||||||
182
src/nodes/items/camera.rs
Normal file
182
src/nodes/items/camera.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
use super::{Item, ItemType};
|
||||||
|
use crate::{
|
||||||
|
core::{
|
||||||
|
client::{Client, INTERNAL_CLIENT},
|
||||||
|
registry::Registry,
|
||||||
|
},
|
||||||
|
nodes::{
|
||||||
|
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES, Drawable},
|
||||||
|
items::TypeInfo,
|
||||||
|
spatial::{find_spatial_parent, parse_transform, Spatial},
|
||||||
|
Message, Node,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use color_eyre::eyre::{bail, Result};
|
||||||
|
use glam::Mat4;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use mint::{RowMatrix4, Vector2};
|
||||||
|
use nanoid::nanoid;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use stardust_xr::{
|
||||||
|
schemas::flex::{deserialize, serialize},
|
||||||
|
values::Transform,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use stereokit::{
|
||||||
|
Color128, Material, Rect, RenderLayer, StereoKitDraw, Tex, TextureType, Transparency,
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
|
||||||
|
type_name: "camera",
|
||||||
|
aliased_local_signals: vec!["frame"],
|
||||||
|
aliased_local_methods: vec![],
|
||||||
|
aliased_remote_signals: vec![],
|
||||||
|
ui: Default::default(),
|
||||||
|
items: Registry::new(),
|
||||||
|
acceptors: Registry::new(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FrameInfo {
|
||||||
|
proj_matrix: Mat4,
|
||||||
|
px_size: Vector2<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CameraItem {
|
||||||
|
space: Arc<Spatial>,
|
||||||
|
frame_info: Mutex<FrameInfo>,
|
||||||
|
sk_tex: OnceCell<Tex>,
|
||||||
|
sk_mat: OnceCell<Arc<Material>>,
|
||||||
|
applied_to: Registry<ModelPart>,
|
||||||
|
apply_to: Registry<ModelPart>,
|
||||||
|
}
|
||||||
|
impl CameraItem {
|
||||||
|
pub fn add_to(node: &Arc<Node>, proj_matrix: Mat4, px_size: Vector2<u32>) {
|
||||||
|
Item::add_to(
|
||||||
|
node,
|
||||||
|
nanoid!(),
|
||||||
|
&ITEM_TYPE_INFO_CAMERA,
|
||||||
|
ItemType::Camera(CameraItem {
|
||||||
|
space: node.spatial.get().unwrap().clone(),
|
||||||
|
frame_info: Mutex::new(FrameInfo {
|
||||||
|
proj_matrix,
|
||||||
|
px_size,
|
||||||
|
}),
|
||||||
|
sk_tex: OnceCell::new(),
|
||||||
|
sk_mat: OnceCell::new(),
|
||||||
|
applied_to: Registry::new(),
|
||||||
|
apply_to: Registry::new(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// node.add_local_method("frame", CameraItem::frame_flex);
|
||||||
|
node.add_local_signal(
|
||||||
|
"apply_preview_material",
|
||||||
|
CameraItem::apply_preview_material_flex,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn frame_flex(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<Message> {
|
||||||
|
// let ItemType::Camera(camera) = &node.item.get().unwrap().specialization else {
|
||||||
|
// return Err(eyre!("Wrong item type?"))
|
||||||
|
// };
|
||||||
|
// Ok(serialize(())?.into())
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn apply_preview_material_flex(
|
||||||
|
node: &Node,
|
||||||
|
calling_client: Arc<Client>,
|
||||||
|
message: Message,
|
||||||
|
) -> Result<()> {
|
||||||
|
let ItemType::Camera(camera) = &node.item.get().unwrap().specialization else {
|
||||||
|
bail!("Wrong item type?")
|
||||||
|
};
|
||||||
|
let model_part_node =
|
||||||
|
calling_client.get_node("Model part", deserialize(&message.data).unwrap())?;
|
||||||
|
let Drawable::ModelPart(model_part) = model_part_node.get_aspect("Model part", "model part", |n| &n.drawable)? else {bail!("Drawable is not a model node")};
|
||||||
|
camera.applied_to.add_raw(model_part);
|
||||||
|
camera.apply_to.add_raw(model_part);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||||
|
Ok(serialize(id)?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&self, sk: &impl StereoKitDraw) {
|
||||||
|
let frame_info = self.frame_info.lock();
|
||||||
|
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||||
|
sk.tex_gen_color(
|
||||||
|
Color128::default(),
|
||||||
|
frame_info.px_size.x as i32,
|
||||||
|
frame_info.px_size.y as i32,
|
||||||
|
TextureType::RENDER_TARGET,
|
||||||
|
stereokit::TextureFormat::RGBA32Linear,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let sk_mat = self.sk_mat.get_or_init(|| {
|
||||||
|
let shader = sk.shader_create_mem(&UNLIT_SHADER_BYTES).unwrap();
|
||||||
|
let mat = sk.material_create(&shader);
|
||||||
|
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
|
||||||
|
sk.material_set_transparency(&mat, Transparency::Blend);
|
||||||
|
Arc::new(mat)
|
||||||
|
});
|
||||||
|
for model_part in self.apply_to.take_valid_contents() {
|
||||||
|
model_part.replace_material(sk_mat.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.applied_to.is_empty() {
|
||||||
|
sk.render_to(
|
||||||
|
sk_tex,
|
||||||
|
frame_info.proj_matrix,
|
||||||
|
self.space.global_transform(),
|
||||||
|
RenderLayer::all(),
|
||||||
|
stereokit::RenderClear::All,
|
||||||
|
Rect {
|
||||||
|
x: 0.0,
|
||||||
|
y: 0.0,
|
||||||
|
w: 0.0,
|
||||||
|
h: 0.0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(sk: &impl StereoKitDraw) {
|
||||||
|
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
|
||||||
|
let ItemType::Camera(camera) = &camera.specialization else {continue};
|
||||||
|
camera.update(sk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn create_camera_item_flex(
|
||||||
|
_node: &Node,
|
||||||
|
calling_client: Arc<Client>,
|
||||||
|
message: Message,
|
||||||
|
) -> Result<()> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct CreateCameraItemInfo<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
parent_path: &'a str,
|
||||||
|
transform: Transform,
|
||||||
|
proj_matrix: RowMatrix4<f32>,
|
||||||
|
px_size: Vector2<u32>,
|
||||||
|
}
|
||||||
|
let info: CreateCameraItemInfo = deserialize(message.as_ref())?;
|
||||||
|
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
|
||||||
|
let space = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||||
|
let transform = parse_transform(info.transform, true, true, false);
|
||||||
|
|
||||||
|
let node =
|
||||||
|
Node::create(&INTERNAL_CLIENT, &parent_name, info.name, false).add_to_scenegraph()?;
|
||||||
|
Spatial::add_to(&node, None, transform * space.global_transform(), false)?;
|
||||||
|
CameraItem::add_to(&node, info.proj_matrix.into(), info.px_size);
|
||||||
|
node.item
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.make_alias_named(&calling_client, &parent_name, info.name)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
pub mod camera;
|
||||||
mod environment;
|
mod environment;
|
||||||
pub mod panel;
|
pub mod panel;
|
||||||
|
|
||||||
|
use self::camera::CameraItem;
|
||||||
use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT};
|
use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT};
|
||||||
use self::panel::{PanelItemTrait, ITEM_TYPE_INFO_PANEL};
|
use self::panel::{PanelItemTrait, ITEM_TYPE_INFO_PANEL};
|
||||||
use super::fields::Field;
|
use super::fields::Field;
|
||||||
@@ -171,12 +173,14 @@ impl Drop for Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
|
Camera(CameraItem),
|
||||||
Environment(EnvironmentItem),
|
Environment(EnvironmentItem),
|
||||||
Panel(Arc<dyn PanelItemTrait>),
|
Panel(Arc<dyn PanelItemTrait>),
|
||||||
}
|
}
|
||||||
impl ItemType {
|
impl ItemType {
|
||||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||||
match self {
|
match self {
|
||||||
|
ItemType::Camera(c) => c.serialize_start_data(id),
|
||||||
ItemType::Environment(e) => e.serialize_start_data(id),
|
ItemType::Environment(e) => e.serialize_start_data(id),
|
||||||
ItemType::Panel(p) => p.serialize_start_data(id),
|
ItemType::Panel(p) => p.serialize_start_data(id),
|
||||||
}
|
}
|
||||||
@@ -384,6 +388,7 @@ impl Drop for ItemAcceptor {
|
|||||||
|
|
||||||
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||||
let node = Node::create(client, "", "item", false);
|
let node = Node::create(client, "", "item", false);
|
||||||
|
node.add_local_signal("create_camera_item", camera::create_camera_item_flex);
|
||||||
node.add_local_signal(
|
node.add_local_signal(
|
||||||
"create_environment_item",
|
"create_environment_item",
|
||||||
environment::create_environment_item_flex,
|
environment::create_environment_item_flex,
|
||||||
|
|||||||
Reference in New Issue
Block a user