use node;
use color::Color;
use hub::{Hub, HubPtr, SubNode};
use object::{Base, DowncastObject, Group, Object};
use texture::{CubeMap, Texture};
use std::mem;
use std::marker::PhantomData;
use std::sync::MutexGuard;
#[derive(Clone, Debug, PartialEq)]
pub enum Background {
Color(Color),
Texture(Texture<[f32; 4]>),
Skybox(CubeMap<[f32; 4]>),
}
pub struct Scene {
pub(crate) hub: HubPtr,
pub(crate) first_child: Option<node::NodePointer>,
pub background: Background,
}
impl Scene {
pub fn add<P>(
&mut self,
child_base: P,
) where
P: AsRef<Base>,
{
let mut hub = self.hub.lock().unwrap();
let node_ptr = child_base.as_ref().node.clone();
let child = &mut hub[child_base];
if child.next_sibling.is_some() {
error!("Element {:?} is added to a scene while still having old parent - {}",
child.sub_node, "discarding siblings");
}
child.next_sibling = mem::replace(&mut self.first_child, Some(node_ptr));
}
pub fn remove<P>(
&mut self,
child_base: P,
) where
P: AsRef<Base>,
{
let target_maybe = Some(child_base.as_ref().node.clone());
let mut hub = self.hub.lock().unwrap();
let next_sibling = hub[child_base].next_sibling.clone();
if self.first_child == target_maybe {
self.first_child = next_sibling;
return;
}
let mut cur_ptr = self.first_child.clone();
while let Some(ptr) = cur_ptr.take() {
let node = &mut hub.nodes[&ptr];
if node.next_sibling == target_maybe {
node.next_sibling = next_sibling;
return;
}
cur_ptr = node.next_sibling.clone(); }
error!("Unable to find child for removal");
}
}
pub struct SyncGuard<'a> {
pub(crate) scene: &'a Scene,
pub(crate) hub: MutexGuard<'a, Hub>,
}
impl<'a> SyncGuard<'a> {
pub fn resolve<T: 'a + Object>(
&self,
object: &T,
) -> node::Node<node::Local> {
self.hub[object].to_node()
}
pub fn resolve_world<T: 'a + Object>(
&self,
object: &T,
) -> node::Node<node::World> {
let internal = &self.hub[object] as *const _;
let wn = self.hub
.walk_all(&self.scene.first_child)
.find(|wn| wn.node as *const _ == internal)
.expect("Unable to find objects for world resolve!");
node::Node {
visible: wn.world_visible,
name: wn.node.name.clone(),
transform: wn.world_transform.into(),
material: match wn.node.sub_node {
SubNode::Visual(ref mat, _, _) => Some(mat.clone()),
_ => None,
},
_space: PhantomData,
}
}
pub fn resolve_data<T: 'a + Object>(
&self,
object: &T,
) -> T::Data {
object.resolve_data(self)
}
pub fn walk_hierarchy(&'a self, root: &Group) -> impl Iterator<Item = Base> + 'a {
let root = root.as_ref().node.clone();
let guard = &*self;
self
.hub
.walk_all(&Some(root))
.map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
}
pub fn find_child_by_name(&self, root: &Group, name: &str) -> Option<Base> {
self.find_children_by_name(root, name).next()
}
pub fn find_children_by_name(
&'a self,
root: &Group,
name: &'a str,
) -> impl Iterator<Item = Base> + 'a {
let root = root.as_ref().node.clone();
let guard = &*self;
self
.hub
.walk_all(&Some(root))
.filter(move |walked| {
walked
.node
.name
.as_ref()
.map(|node_name| node_name == name)
.unwrap_or(false)
})
.map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
}
pub fn find_child_of_type<T: DowncastObject>(&'a self, root: &Group) -> Option<T> {
self.find_children_of_type::<T>(root).next()
}
pub fn find_children_of_type<T: DowncastObject>(
&'a self,
root: &Group,
) -> impl Iterator<Item = T> + 'a {
let root = root.as_ref().node.clone();
let guard = &*self;
self
.hub
.walk_all(&Some(root))
.map(move |walked| guard.hub.upgrade_ptr(walked.node_ptr.clone()))
.filter_map(move |base| guard.downcast(&base))
}
pub fn find_child_of_type_by_name<T: DowncastObject>(
&'a self,
root: &Group,
name: &'a str,
) -> Option<T> {
self.find_children_of_type_by_name(root, name).next()
}
pub fn find_children_of_type_by_name<T: DowncastObject>(
&'a self,
root: &Group,
name: &'a str,
) -> impl Iterator<Item = T> + 'a {
let guard = &*self;
self
.find_children_by_name(root, name)
.filter_map(move |base| guard.downcast(&base))
}
pub fn downcast<T: DowncastObject>(&self, base: &Base) -> Option<T> {
let object_type = self.resolve_data(base);
T::downcast(object_type)
}
}
impl Scene {
pub fn sync_guard(&mut self) -> SyncGuard {
let mut hub = self.hub.lock().unwrap();
hub.process_messages();
SyncGuard { scene: self, hub }
}
}