/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2024 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
use async_channel::Sender;
use async_lock::Mutex;
use darkfi_serial::{
async_trait, deserialize, Decodable, Encodable, FutAsyncWriteExt, ReadExt, SerialDecodable,
SerialEncodable, VarInt,
};
use futures::{stream::FuturesUnordered, StreamExt};
use std::{fmt, str::FromStr, sync::Arc};
use crate::{
error::{Error, Result},
prop::{Property, PropertyPtr, PropertyType, Role},
ui,
};
pub type SceneNodeId = u32;
#[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
#[repr(u8)]
pub enum SceneNodeType {
Null = 0,
Root = 1,
Window = 2,
WindowInput = 6,
Keyboard = 7,
Mouse = 8,
RenderLayer = 3,
RenderObject = 4,
RenderMesh = 5,
RenderText = 9,
RenderTexture = 13,
Fonts = 10,
Font = 11,
Plugins = 14,
Plugin = 15,
ChatView = 16,
EditBox = 17,
Image = 18,
Button = 19,
}
pub struct ScenePath(Vec);
impl> From for ScenePath {
fn from(path: S) -> Self {
let path: String = path.into();
(&path).parse().expect("invalid ScenePath &str")
}
}
impl fmt::Display for ScenePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "/")?;
for token in &self.0 {
write!(f, "{}/", token)?;
}
Ok(())
}
}
impl FromStr for ScenePath {
type Err = Error;
fn from_str(s: &str) -> Result {
if s.is_empty() || s.chars().nth(0).unwrap() != '/' {
return Err(Error::InvalidScenePath);
}
if s == "/" {
return Ok(ScenePath(vec![]));
}
let mut tokens = s.split('/');
// Should start with a /
let initial = tokens.next().expect("should not be empty");
if !initial.is_empty() {
return Err(Error::InvalidScenePath);
}
let mut path = vec![];
for token in tokens {
// There should not be any double slashes //
if token.is_empty() {
return Err(Error::InvalidScenePath);
}
path.push(token.to_string());
}
Ok(ScenePath(path))
}
}
pub type SceneGraphPtr = Arc>;
pub type SceneGraphPtr2 = Arc>;
pub struct SceneGraph {
// Node 0 is always the root
nodes: Vec,
freed: Vec,
}
impl SceneGraph {
pub const ROOT_ID: SceneNodeId = 0;
pub fn new() -> Self {
let root = SceneNode {
name: "/".to_string(),
id: 0,
typ: SceneNodeType::Root,
parents: vec![],
children: vec![],
props: vec![],
sigs: vec![],
methods: vec![],
pimpl: Pimpl::Null,
};
Self { nodes: vec![root], freed: vec![] }
}
pub fn add_node>(&mut self, name: S, typ: SceneNodeType) -> &mut SceneNode {
let node = SceneNode {
name: name.into(),
// We set this at the end
id: 0,
typ,
parents: vec![],
children: vec![],
props: vec![],
sigs: vec![],
methods: vec![],
pimpl: Pimpl::Null,
};
let node_id = if self.freed.is_empty() {
let node_id = self.nodes.len() as SceneNodeId;
self.nodes.push(node);
node_id
} else {
let node_id = self.freed.pop().unwrap();
let _ = std::mem::replace(&mut self.nodes[node_id as usize], node);
node_id
};
self.nodes[node_id as usize].id = node_id;
&mut self.nodes[node_id as usize]
}
pub fn remove_node(&mut self, id: SceneNodeId) -> Result<()> {
let node = self.get_node_mut(id).ok_or(Error::NodeNotFound)?;
if !node.parents.is_empty() {
return Err(Error::NodeHasParents);
}
if !node.children.is_empty() {
return Err(Error::NodeHasChildren);
}
node.name.clear();
node.typ = SceneNodeType::Null;
node.props.clear();
self.freed.push(id);
Ok(())
}
fn root(&self) -> &SceneNode {
&self.nodes[0]
}
fn root_mut(&mut self) -> &mut SceneNode {
&mut self.nodes[0]
}
fn exists(&self, id: SceneNodeId) -> bool {
id < self.nodes.len() as SceneNodeId && !self.freed.contains(&id)
}
pub fn get_node(&self, id: SceneNodeId) -> Option<&SceneNode> {
if self.exists(id) {
Some(&self.nodes[id as usize])
} else {
None
}
}
pub fn get_node_mut(&mut self, id: SceneNodeId) -> Option<&mut SceneNode> {
if self.exists(id) {
Some(&mut self.nodes[id as usize])
} else {
None
}
}
pub fn link(&mut self, child_id: SceneNodeId, parent_id: SceneNodeId) -> Result<()> {
// Check both nodes are not already linked
let is_linked = self.is_linked(child_id, parent_id)?;
if is_linked {
return Err(Error::NodesAreLinked);
}
let parent = self.get_node(parent_id).unwrap();
let parent_inf =
SceneNodeInfo { name: parent.name.clone(), id: parent_id, typ: parent.typ };
let child_name = &self.get_node(child_id).unwrap().name;
if parent.has_child(child_name) {
return Err(Error::NodeChildNameConflict);
}
// Link parent into child
let child = self.get_node_mut(child_id).unwrap();
if child.has_parent(&parent_inf.name) {
return Err(Error::NodeParentNameConflict);
}
let child_inf = SceneNodeInfo { name: child.name.clone(), id: child_id, typ: child.typ };
assert!(!child.has_parent_id(parent_id));
child.parents.push(parent_inf);
// Link child into parent
let parent = self.get_node_mut(parent_id).unwrap();
assert!(!parent.has_child(&child_inf.name));
parent.children.push(child_inf);
Ok(())
}
pub fn unlink(&mut self, child_id: SceneNodeId, parent_id: SceneNodeId) -> Result<()> {
// Check both nodes are actually linked
let is_linked = self.is_linked(child_id, parent_id)?;
if !is_linked {
return Err(Error::NodesNotLinked);
}
// Unlink parent from child
let child = self.get_node_mut(child_id).unwrap();
child.remove_parent(parent_id);
// Unlink child from parent
let parent = self.get_node_mut(parent_id).unwrap();
parent.remove_child(child_id);
Ok(())
}
pub fn is_linked(&self, child_id: SceneNodeId, parent_id: SceneNodeId) -> Result {
let parent = self.get_node(parent_id).ok_or(Error::ParentNodeNotFound)?;
let child = self.get_node(child_id).ok_or(Error::ChildNodeNotFound)?;
let parent_has_child = parent.has_child_id(child_id);
let child_has_parent = child.has_parent_id(parent_id);
// Internal consistency checks
if parent_has_child {
assert!(child_has_parent);
} else {
assert!(!child_has_parent);
}
Ok(parent_has_child)
}
pub fn lookup_node_id>(&self, path: P) -> Option {
let path: ScenePath = path.into();
let mut current_id = Self::ROOT_ID;
for node_name in path.0 {
let parent_node = self.get_node(current_id).unwrap();
match parent_node.get_child(&node_name) {
Some(child_id) => {
current_id = child_id;
}
None => return None,
}
}
Some(current_id)
}
pub fn lookup_node>(&self, path: P) -> Option<&SceneNode> {
let node_id = self.lookup_node_id(path)?;
Some(self.get_node(node_id).unwrap())
}
pub fn lookup_node_mut>(&mut self, path: P) -> Option<&mut SceneNode> {
let node_id = self.lookup_node_id(path)?;
Some(self.get_node_mut(node_id).unwrap())
}
pub fn rename_node>(
&mut self,
node_id: SceneNodeId,
node_name: S,
) -> Result<()> {
let node_name = node_name.into();
for sibling_inf in self.node_siblings(node_id)? {
if sibling_inf.name == node_name {
return Err(Error::NodeSiblingNameConflict)
}
}
let node = self.get_node_mut(node_id).unwrap();
node.name = node_name.clone();
// Now update it for all children and parents too
let parent_ids: Vec<_> = node.parents.iter().map(|parent_inf| parent_inf.id).collect();
let child_ids: Vec<_> = node.children.iter().map(|child_inf| child_inf.id).collect();
'next_parent: for parent_id in parent_ids {
let parent = self.get_node_mut(parent_id).unwrap();
for child in &mut parent.children {
if child.id == node_id {
child.name = node_name.clone();
continue 'next_parent
}
}
panic!("child {} not found in parent {}!", node_id, parent.id)
}
'next_child: for child_id in child_ids {
let child = self.get_node_mut(child_id).unwrap();
for parent in &mut child.parents {
if parent.id == node_id {
parent.name = node_name.clone();
continue 'next_child
}
}
panic!("parent {} not found in child {}!", node_id, child.id)
}
Ok(())
}
fn node_siblings(&self, node_id: SceneNodeId) -> Result> {
let mut siblings = vec![];
let node = self.get_node(node_id).ok_or(Error::NodeNotFound)?;
for parent_inf in &node.parents {
let parent = self.get_node(parent_inf.id).ok_or(Error::ParentNodeNotFound)?;
let mut sibling_infs = parent
.children
.iter()
.cloned()
.filter(|child_inf| child_inf.id != node_id)
.collect();
siblings.append(&mut sibling_infs);
}
Ok(siblings)
}
pub fn scan_dangling(&self) -> Vec {
let mut dangling = vec![];
for node in &self.nodes {
if node.id == Self::ROOT_ID {
continue
}
if self.freed.contains(&node.id) {
continue
}
if node.parents.is_empty() {
dangling.push(node.id);
}
}
dangling
}
}
#[derive(Clone)]
pub struct SceneNodeInfo {
pub name: String,
pub id: SceneNodeId,
pub typ: SceneNodeType,
}
pub struct SceneNode {
pub name: String,
pub id: SceneNodeId,
pub typ: SceneNodeType,
pub parents: Vec,
pub children: Vec,
pub props: Vec,
pub sigs: Vec,
pub methods: Vec,
pub pimpl: Pimpl,
}
impl SceneNode {
fn has_parent_id(&self, parent_id: SceneNodeId) -> bool {
self.parents.iter().any(|parent| parent.id == parent_id)
}
fn has_child_id(&self, child_id: SceneNodeId) -> bool {
self.children.iter().any(|child| child.id == child_id)
}
fn has_parent(&self, parent_name: &str) -> bool {
self.parents.iter().any(|parent| parent.name == parent_name)
}
fn has_child(&self, child_name: &str) -> bool {
self.children.iter().any(|child| child.name == child_name)
}
fn get_child(&self, child_name: &str) -> Option {
for child in &self.children {
if child.name == child_name {
return Some(child.id);
}
}
None
}
// Panics if parent is not linked
fn remove_parent(&mut self, parent_id: SceneNodeId) {
let parent_idx = self.parents.iter().position(|parent| parent.id == parent_id).unwrap();
self.parents.swap_remove(parent_idx);
}
// Panics if child is not linked
fn remove_child(&mut self, child_id: SceneNodeId) {
let child_idx = self.children.iter().position(|child| child.id == child_id).unwrap();
self.children.swap_remove(child_idx);
}
pub fn get_children(&self, allowed_types: &[SceneNodeType]) -> Vec {
self.children
.iter()
.cloned()
.filter(move |child_inf| allowed_types.contains(&child_inf.typ))
.collect()
}
pub fn get_children2(&self) -> Vec {
self.children.iter().cloned().collect()
}
pub fn add_property(&mut self, prop: Property) -> Result<()> {
if self.has_property(&prop.name) {
return Err(Error::PropertyAlreadyExists);
}
self.props.push(Arc::new(prop));
Ok(())
}
fn has_property(&self, name: &str) -> bool {
self.props.iter().any(|prop| prop.name == name)
}
pub fn get_property(&self, name: &str) -> Option {
self.props.iter().find(|prop| prop.name == name).map(|prop| prop.clone())
}
// Convenience methods
pub fn get_property_bool(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_bool(0)
}
pub fn get_property_u32(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_u32(0)
}
pub fn get_property_f32(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_f32(0)
}
pub fn get_property_str(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_str(0)
}
pub fn get_property_enum(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_enum(0)
}
pub fn get_property_node_id(&self, name: &str) -> Result {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_node_id(0)
}
// Setters
pub fn set_property_bool(&self, role: Role, name: &str, val: bool) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_bool(role, 0, val)
}
pub fn set_property_u32(&self, role: Role, name: &str, val: u32) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_u32(role, 0, val)
}
pub fn set_property_f32(&self, role: Role, name: &str, val: f32) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_f32(role, 0, val)
}
pub fn set_property_str>(&self, role: Role, name: &str, val: S) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_str(role, 0, val)
}
pub fn set_property_node_id(&self, role: Role, name: &str, val: SceneNodeId) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_node_id(role, 0, val)
}
pub fn add_signal>(
&mut self,
name: S,
desc: S,
fmt: Vec<(S, S, CallArgType)>,
) -> Result<()> {
let name = name.into();
if self.has_signal(&name) {
return Err(Error::SignalAlreadyExists);
}
let fmt = fmt
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
self.sigs.push(Signal {
name: name.into(),
desc: desc.into(),
fmt,
slots: vec![],
freed: vec![],
});
Ok(())
}
fn has_signal(&self, name: &str) -> bool {
self.sigs.iter().any(|sig| sig.name == name)
}
pub fn get_signal(&self, name: &str) -> Option<&Signal> {
self.sigs.iter().find(|sig| sig.name == name)
}
fn get_signal_mut(&mut self, name: &str) -> Option<&mut Signal> {
self.sigs.iter_mut().find(|sig| sig.name == name)
}
pub fn register(&mut self, sig_name: &str, slot: Slot) -> Result {
let sig = self.get_signal_mut(sig_name).ok_or(Error::SignalNotFound)?;
let slot_id = if sig.freed.is_empty() {
let slot_id = sig.slots.len() as SlotId;
sig.slots.push(slot);
slot_id
} else {
let slot_id = sig.freed.pop().unwrap();
let _ = std::mem::replace(&mut sig.slots[slot_id as usize], slot);
slot_id
};
Ok(slot_id)
}
pub fn unregister(&mut self, sig_name: &str, slot_id: SlotId) -> Result<()> {
let sig = self.get_signal_mut(sig_name).ok_or(Error::SignalNotFound)?;
if !sig.slot_exists(slot_id) {
return Err(Error::SlotNotFound);
}
sig.freed.push(slot_id);
Ok(())
}
pub async fn trigger(&self, sig_name: &str, data: Vec) -> Result<()> {
let sig = self.get_signal(sig_name).ok_or(Error::SignalNotFound)?;
let futures = FuturesUnordered::new();
// TODO: autoremove slots which fail to send
for (_, slot) in sig.get_slots() {
debug!(target: "scene", "triggering {}", slot.name);
// Trigger the slot
futures.push(async { slot.notify.send(data.clone()).await.is_ok() });
}
let success: Vec<_> = futures.collect().await;
debug!(target: "scene", "trigger success: {success:?}");
Ok(())
}
pub fn add_method>(
&mut self,
name: S,
args: Vec<(S, S, CallArgType)>,
result: Vec<(S, S, CallArgType)>,
method_fn: MethodRequestFn,
) -> Result<()> {
let name = name.into();
if self.has_signal(&name) {
return Err(Error::MethodAlreadyExists);
}
let args = args
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
let result = result
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
self.methods.push(Method { name: name.into(), args, result, method_fn });
Ok(())
}
pub fn get_method(&self, name: &str) -> Option<&Method> {
self.methods.iter().find(|method| method.name == name)
}
fn get_method_mut(&mut self, name: &str) -> Option<&mut Method> {
self.methods.iter_mut().find(|method| method.name == name)
}
pub fn call_method(
&mut self,
name: &str,
arg_data: Vec,
response_fn: MethodResponseFn,
) -> Result<()> {
let method = self.get_method(name).ok_or(Error::MethodNotFound)?;
(method.method_fn)(arg_data, response_fn);
Ok(())
}
}
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub enum CallArgType {
Uint32,
Uint64,
Bool,
Str,
Hash,
}
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub struct CallArg {
pub name: String,
pub desc: String,
pub typ: CallArgType,
}
type SlotFn = Box) + Send>;
pub type SlotId = u32;
pub struct Slot {
pub name: String,
pub notify: Sender>,
}
pub struct Signal {
pub name: String,
pub desc: String,
pub fmt: Vec,
slots: Vec,
freed: Vec,
}
impl Signal {
fn slot_exists(&self, slot_id: SlotId) -> bool {
if slot_id >= self.slots.len() as SlotId {
return false;
}
return !self.freed.contains(&slot_id);
}
pub fn get_slots<'a>(&'a self) -> impl Iterator- {
self.slots
.iter()
.enumerate()
.filter(|(slot_id, _)| !self.freed.contains(&(*slot_id as SlotId)))
.map(|(slot_id, slot)| (slot_id as SlotId, slot))
}
pub fn lookup_slot_id(&self, slot_name: &str) -> Option {
for (slot_id, slot) in self.get_slots() {
if slot.name == slot_name {
return Some(slot_id);
}
}
None
}
}
type MethodRequestFn = Box, MethodResponseFn) + Send + Sync>;
pub type MethodResponseFn = Box>) + Send + Sync>;
pub struct Method {
pub name: String,
pub args: Vec,
pub result: Vec,
method_fn: MethodRequestFn,
}
pub enum Pimpl {
Null,
Window(ui::WindowPtr),
RenderLayer(ui::RenderLayerPtr),
Mesh(ui::MeshPtr),
Text(ui::TextPtr),
EditBox(ui::EditBoxPtr),
ChatView(ui::ChatViewPtr),
Image(ui::ImagePtr),
Button(ui::ButtonPtr),
}
impl std::fmt::Debug for SceneNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "'{}':{}", self.name, self.id)
}
}