feat(drawable): text

This commit is contained in:
Nova
2022-09-26 07:09:37 -04:00
parent 2a5c11c0f0
commit 12668419ce
6 changed files with 236 additions and 10 deletions

View File

@@ -32,7 +32,7 @@ prisma = "0.1.1"
slog = "2.7.0"
slog-stdlog = "4.1.1"
xkbcommon = { version = "0.5.0", default-features = false }
stardust-xr = "0.3.0"
stardust-xr = "0.3.1"
stardust-xr-schemas = "0.1.0"
stereokit = {default-features = false, features = ["linux-egl"], version = "0.2.0"}
wayland-backend = "=0.1.0-beta.9"

View File

@@ -1,4 +1,5 @@
pub mod model;
pub mod text;
use super::Node;
use crate::core::client::Client;
@@ -9,13 +10,15 @@ use stereokit::{lifecycle::DrawContext, texture::Texture, StereoKit};
pub fn create_interface(client: &Arc<Client>) {
let node = Node::create(client, "", "drawable", false);
node.add_local_signal("createModel", model::create);
node.add_local_signal("createModel", model::create_flex);
node.add_local_signal("createText", text::create_flex);
node.add_local_signal("setSkyFile", set_sky_file_flex);
node.add_to_scenegraph();
}
pub fn draw(sk: &mut StereoKit, draw_ctx: &DrawContext) {
model::draw_all(sk, draw_ctx);
text::draw_all(sk, draw_ctx);
let new_skytex = QUEUED_SKYTEX.lock().take();
let mut new_skylight = QUEUED_SKYLIGHT.lock().take();

View File

@@ -163,7 +163,7 @@ pub fn draw_all(sk: &StereoKit, draw_ctx: &DrawContext) {
}
}
pub fn create(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let node = Node::create(
&calling_client,

220
src/nodes/drawable/text.rs Normal file
View File

@@ -0,0 +1,220 @@
use crate::{
core::{
client::Client,
destroy_queue,
registry::Registry,
resource::{parse_resource_id, ResourceID},
},
nodes::{
spatial::{get_spatial_parent_flex, parse_transform, Spatial},
Node,
},
};
use anyhow::{anyhow, ensure, Result};
use glam::{vec3, Mat4, Vec2};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use prisma::{FromTuple, Rgb, Rgba};
use send_wrapper::SendWrapper;
use stardust_xr::values::{parse_f32, parse_vec2};
use std::{convert::TryFrom, path::PathBuf, sync::Arc};
use stereokit::{
font::Font,
lifecycle::DrawContext,
text::{self, TextAlign, TextFit, TextStyle},
StereoKit,
};
static TEXT_REGISTRY: Registry<Text> = Registry::new();
struct TextData {
text: String,
character_height: f32,
text_align: TextAlign,
bounds: Option<Vec2>,
fit: TextFit,
bounds_align: TextAlign,
color: Rgba<f32>,
}
pub struct Text {
space: Arc<Spatial>,
font_path: Option<PathBuf>,
style: OnceCell<SendWrapper<TextStyle>>,
data: Mutex<TextData>,
}
impl Text {
#[allow(clippy::too_many_arguments)]
pub fn add_to(
node: &Arc<Node>,
font_resource_id: Option<ResourceID>,
text: String,
character_height: f32,
text_align: TextAlign,
bounds: Option<Vec2>,
fit: TextFit,
bounds_align: TextAlign,
color: Rgba<f32>,
) -> Result<Arc<Text>> {
ensure!(
node.spatial.get().is_some(),
"Internal: Node does not have a spatial attached!"
);
ensure!(
node.model.get().is_none(),
"Internal: Node already has text attached!"
);
let text = TEXT_REGISTRY.add(Text {
space: node.spatial.get().unwrap().clone(),
font_path: font_resource_id.and_then(|res| {
res.get_file(&node.get_client().base_resource_prefixes.lock().clone())
}),
style: OnceCell::new(),
data: Mutex::new(TextData {
text,
character_height,
text_align,
bounds,
fit,
bounds_align,
color,
}),
});
node.add_local_signal("setCharacterHeight", Text::set_character_height_flex);
node.add_local_signal("setText", Text::set_text_flex);
let _ = node.text.set(text.clone());
Ok(text)
}
fn draw(&self, sk: &StereoKit, draw_ctx: &DrawContext) {
let style =
self.style
.get_or_try_init(|| -> Result<SendWrapper<TextStyle>, anyhow::Error> {
let font = if let Some(path) = self.font_path.as_deref() {
Font::from_file(sk, path)
} else {
Some(Font::default(sk))
};
Ok(SendWrapper::new(TextStyle::new(
sk,
font.ok_or(std::fmt::Error)?,
1.0,
Rgba::new(Rgb::new(1.0, 1.0, 1.0), 1.0),
)))
});
if let Ok(style) = style {
let data = self.data.lock();
let transform = self.space.global_transform()
* Mat4::from_scale(vec3(
data.character_height,
data.character_height,
data.character_height,
));
if let Some(bounds) = data.bounds {
text::draw_in(
draw_ctx,
&data.text,
transform,
bounds / data.character_height,
data.fit,
style,
data.bounds_align,
data.text_align,
vec3(0.0, 0.0, 0.0),
data.color,
);
} else {
text::draw_at(
draw_ctx,
&data.text,
transform,
style,
data.bounds_align,
data.text_align,
vec3(0.0, 0.0, 0.0),
data.color,
);
}
}
}
pub fn set_character_height_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let height = flexbuffers::Reader::get_root(data)?.get_f64()? as f32;
node.text.get().unwrap().data.lock().character_height = height;
Ok(())
}
pub fn set_text_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let text = flexbuffers::Reader::get_root(data)?.get_str()?.to_string();
node.text.get().unwrap().data.lock().text = text;
Ok(())
}
}
impl Drop for Text {
fn drop(&mut self) {
if let Some(style) = self.style.take() {
destroy_queue::add(style);
}
TEXT_REGISTRY.remove(self);
}
}
pub fn draw_all(sk: &StereoKit, draw_ctx: &DrawContext) {
for text in TEXT_REGISTRY.get_valid_contents() {
text.draw(sk, draw_ctx);
}
}
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let node = Node::create(
&calling_client,
"/drawable/text",
flex_vec.idx(0).get_str()?,
true,
);
let parent = get_spatial_parent_flex(&calling_client, flex_vec.index(1)?.get_str()?)?;
let transform = parse_transform(flex_vec.index(2)?, true, true, true)?;
let text = flex_vec.index(3)?.get_str()?.to_string();
let font_resource_id = parse_resource_id(flex_vec.index(4)?).ok();
let character_height = flex_vec.index(5)?.get_f64()? as f32;
let text_align = TextAlign::from_bits(flex_vec.index(6)?.get_u64()? as u32)
.ok_or_else(|| anyhow!("Text align bitflag out of range"))?;
let bounds = parse_vec2(flex_vec.index(7)?).map(|bounds| bounds.into());
let fit = TextFit::try_from(flex_vec.index(8)?.get_u64()? as u32)?;
let bounds_align = TextAlign::from_bits(flex_vec.index(9)?.get_u64()? as u32)
.ok_or_else(|| anyhow!("Bounds align bitflag out of range"))?;
let color_vec = flex_vec.index(10)?.get_vector()?;
let color = Rgba::from_tuple((
(
parse_f32(color_vec.index(0)?).ok_or_else(|| anyhow!("Value in color invalid"))?,
parse_f32(color_vec.index(0)?).ok_or_else(|| anyhow!("Value in color invalid"))?,
parse_f32(color_vec.index(0)?).ok_or_else(|| anyhow!("Value in color invalid"))?,
),
parse_f32(color_vec.index(0)?).ok_or_else(|| anyhow!("Value in color invalid"))?,
));
let node = node.add_to_scenegraph();
Spatial::add_to(&node, Some(parent), transform)?;
Text::add_to(
&node,
font_resource_id,
text,
character_height,
text_align,
bounds,
fit,
bounds_align,
color,
)?;
Ok(())
}

View File

@@ -29,6 +29,7 @@ use self::alias::Alias;
use self::data::{PulseReceiver, PulseSender};
use self::drawable::model::Model;
use self::drawable::text::Text;
use self::fields::Field;
use self::input::{InputHandler, InputMethod};
use self::items::{Item, ItemAcceptor, ItemUI};
@@ -58,6 +59,7 @@ pub struct Node {
// Drawable
pub model: OnceCell<Arc<Model>>,
pub text: OnceCell<Arc<Text>>,
// Input
pub input_method: OnceCell<Arc<InputMethod>>,
@@ -106,14 +108,15 @@ impl Node {
spatial: OnceCell::new(),
field: OnceCell::new(),
model: OnceCell::new(),
pulse_sender: OnceCell::new(),
pulse_receiver: OnceCell::new(),
model: OnceCell::new(),
text: OnceCell::new(),
input_method: OnceCell::new(),
input_handler: OnceCell::new(),
item: OnceCell::new(),
item_acceptor: OnceCell::new(),
item_ui: OnceCell::new(),
input_method: OnceCell::new(),
input_handler: OnceCell::new(),
startup_settings: OnceCell::new(),
};
node.add_local_signal("destroy", Node::destroy_flex);
@@ -206,7 +209,7 @@ impl Node {
let data = data.to_vec();
if let Some(messenger) = client.messenger.as_ref() {
let _ = messenger.send_remote_signal(path.as_str(), method.as_str(), data.as_slice());
messenger.send_remote_signal(path.as_str(), method.as_str(), data.as_slice());
}
Ok(())
}

View File

@@ -277,15 +277,15 @@ pub fn parse_transform<B: flexbuffers::Buffer>(
let translation = translation
.then(|| parse_vec3(transform_vec.idx(0)))
.flatten()
.unwrap_or(Vector3::from([0.0; 3]));
.unwrap_or_else(|| Vector3::from([0.0; 3]));
let rotation = rotation
.then(|| parse_quat(transform_vec.idx(1)))
.flatten()
.unwrap_or(Quat::IDENTITY.into());
.unwrap_or_else(|| Quat::IDENTITY.into());
let scale = scale
.then(|| parse_vec3(transform_vec.idx(2)))
.flatten()
.unwrap_or(Vector3::from([1.0; 3]));
.unwrap_or_else(|| Vector3::from([1.0; 3]));
Ok(Mat4::from_scale_rotation_translation(
scale.into(),