use std::fmt;
use std::hash::{Hash, Hasher};
use std::sync::mpsc;
use mint;
use audio;
use camera::Camera;
use hub::{Hub, Message, Operation, SubLight, SubNode};
use light;
use mesh::Mesh;
use node::NodePointer;
use scene::SyncGuard;
use skeleton::{Bone, Skeleton};
use sprite::Sprite;
use text::Text;
#[derive(Clone)]
pub struct Base {
pub(crate) node: NodePointer,
pub(crate) tx: mpsc::Sender<Message>,
}
pub trait Object: AsRef<Base> {
type Data;
fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data;
fn upcast(&self) -> Base {
self.as_ref().clone()
}
fn set_visible(
&self,
visible: bool,
) {
self.as_ref().send(Operation::SetVisible(visible));
}
fn set_name<S: Into<String>>(
&self,
name: S,
) {
self.as_ref().send(Operation::SetName(name.into()));
}
fn set_transform<P, Q>(
&self,
pos: P,
rot: Q,
scale: f32,
) where
Self: Sized,
P: Into<mint::Point3<f32>>,
Q: Into<mint::Quaternion<f32>>,
{
self.as_ref().send(Operation::SetTransform(Some(pos.into()), Some(rot.into()), Some(scale)));
}
fn set_position<P>(
&self,
pos: P,
) where
Self: Sized,
P: Into<mint::Point3<f32>>,
{
self.as_ref().send(Operation::SetTransform(Some(pos.into()), None, None));
}
fn set_orientation<Q>(
&self,
rot: Q,
) where
Self: Sized,
Q: Into<mint::Quaternion<f32>>,
{
self.as_ref().send(Operation::SetTransform(None, Some(rot.into()), None));
}
fn set_scale(
&self,
scale: f32,
) {
self.as_ref().send(Operation::SetTransform(None, None, Some(scale)));
}
fn set_weights(
&self,
weights: Vec<f32>,
) {
self.as_ref().send(Operation::SetWeights(weights));
}
fn look_at<E, T>(
&self,
eye: E,
target: T,
up: Option<mint::Vector3<f32>>,
) where
Self: Sized,
E: Into<mint::Point3<f32>>,
T: Into<mint::Point3<f32>>,
{
use cgmath::{InnerSpace, Point3, Quaternion, Rotation, Vector3};
let p: [mint::Point3<f32>; 2] = [eye.into(), target.into()];
let dir = (Point3::from(p[0]) - Point3::from(p[1])).normalize();
let z = Vector3::unit_z();
let up = match up {
Some(v) => Vector3::from(v).normalize(),
None if dir.dot(z).abs() < 0.99 => z,
None => Vector3::unit_y(),
};
let q = Quaternion::look_at(dir, up).invert();
self.as_ref().send(Operation::SetTransform(Some(p[0]), Some(q.into()), None));
}
}
impl PartialEq for Base {
fn eq(
&self,
other: &Base,
) -> bool {
self.node == other.node
}
}
impl Eq for Base {}
impl Hash for Base {
fn hash<H: Hasher>(
&self,
state: &mut H,
) {
self.node.hash(state);
}
}
impl fmt::Debug for Base {
fn fmt(
&self,
f: &mut fmt::Formatter,
) -> fmt::Result {
self.node.fmt(f)
}
}
impl Base {
pub(crate) fn send(
&self,
operation: Operation,
) {
let _ = self.tx.send((self.node.downgrade(), operation));
}
}
impl AsRef<Base> for Base {
fn as_ref(&self) -> &Base {
self
}
}
impl Object for Base {
type Data = ObjectType;
fn resolve_data(&self, sync_guard: &SyncGuard) -> Self::Data {
match &sync_guard.hub[self].sub_node {
SubNode::Camera(..) => ObjectType::Camera(Camera {
object: self.clone(),
}),
SubNode::Group { .. } => ObjectType::Group(Group {
object: self.clone(),
}),
SubNode::Audio(..) => ObjectType::AudioSource(audio::Source {
object: self.clone(),
}),
SubNode::UiText(..) => ObjectType::Text(Text {
object: self.clone(),
}),
SubNode::Visual(..) => ObjectType::Mesh(Mesh {
object: self.clone(),
}),
SubNode::Bone { .. } => ObjectType::Bone(Bone {
object: self.clone(),
}),
SubNode::Skeleton(..) => ObjectType::Skeleton(Skeleton {
object: self.clone(),
}),
SubNode::Light(light) => match light.sub_light {
SubLight::Ambient => ObjectType::AmbientLight(light::Ambient {
object: self.clone(),
}),
SubLight::Directional => ObjectType::DirectionalLight(light::Directional {
object: self.clone(),
}),
SubLight::Point => ObjectType::PointLight(light::Point {
object: self.clone(),
}),
SubLight::Hemisphere { .. } => ObjectType::HemisphereLight(light::Hemisphere {
object: self.clone(),
}),
},
}
}
}
#[derive(Debug, Clone)]
pub enum ObjectType {
AudioSource(audio::Source),
AmbientLight(light::Ambient),
DirectionalLight(light::Directional),
HemisphereLight(light::Hemisphere),
PointLight(light::Point),
Mesh(Mesh),
Group(Group),
Skeleton(Skeleton),
Bone(Bone),
Sprite(Sprite),
Text(Text),
Camera(Camera),
}
pub trait DowncastObject: Object + Sized {
fn downcast(object: ObjectType) -> Option<Self>;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Group {
object: Base,
}
impl AsRef<Base> for Group {
fn as_ref(&self) -> &Base { &self.object }
}
impl Object for Group {
type Data = Vec<Base>;
fn resolve_data(&self, sync_guard: &SyncGuard) -> Vec<Base> {
let mut children = Vec::new();
let mut child = match &sync_guard.hub[self].sub_node {
SubNode::Group { ref first_child } => first_child.clone(),
sub_node @ _ => panic!("`Group` had a bad sub node type: {:?}", sub_node),
};
while let Some(child_pointer) = child {
child = sync_guard.hub.nodes[&child_pointer].next_sibling.clone();
children.push(Base {
node: child_pointer,
tx: sync_guard.hub.message_tx.clone(),
});
}
children
}
}
derive_DowncastObject!(Group => ObjectType::Group);
impl Group {
pub(crate) fn new(hub: &mut Hub) -> Self {
let sub = SubNode::Group { first_child: None };
Group {
object: hub.spawn(sub),
}
}
pub fn add<T: Object>(
&self,
child: &T,
) {
let node = child.as_ref().node.clone();
self.as_ref().send(Operation::AddChild(node));
}
pub fn remove<T: Object>(
&self,
child: &T,
) {
let node = child.as_ref().node.clone();
self.as_ref().send(Operation::RemoveChild(node));
}
}