use node;
use color::Color;
use hub::{Hub, HubPtr, SubNode};
use object::{Base, 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> {
scene: &'a Scene,
hub: MutexGuard<'a, Hub>,
}
impl<'a> SyncGuard<'a> {
pub fn resolve<T: 'a + Object>(
&mut self,
object: &T,
) -> node::Node<node::Local> {
self.hub[object].to_node()
}
pub fn resolve_world<T: 'a + Object>(
&mut 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,
transform: wn.world_transform.into(),
material: match wn.node.sub_node {
SubNode::Visual(ref mat, _, _) => Some(mat.clone()),
_ => None,
},
_space: PhantomData,
}
}
}
impl Scene {
pub fn sync_guard(&mut self) -> SyncGuard {
let mut hub = self.hub.lock().unwrap();
hub.process_messages();
SyncGuard { scene: self, hub }
}
}