use na::*;
use angle::*;
use util::ValueCache;
use std::ops::Mul;
use alga::general::{Identity, Multiplicative};
use std::fmt::{self, Debug};
bitflags!{
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Flags: u16{
const NO_ROTATION_FROM_PARENT = 1 << 0;
const NO_SCALE_FROM_PARENT = 1 << 1;
const NO_TRANSLATION_FROM_PARENT = 1 << 2;
}
}
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Node{
position: ValueCache<Pnt3>,
orientation: ValueCache<UnitQuat>,
scale: ValueCache<Vec3>,
local_transformation: ValueCache<Mat4>,
global_transformation: ValueCache<Mat4>,
global_scale: ValueCache<Vec3>,
parent_inv: Option<Mat4>,
}
fn trafo_from_parts(pos: &Pnt3, orientation: &UnitQuat, scale: &Vec3) -> Mat4{
let scale = Mat3::from_diagonal(scale);
let rot = orientation.to_rotation_matrix();
let mat = rot * scale;
Mat4::from_columns(&[
vec4!(mat.column(0), 0.),
vec4!(mat.column(1), 0.),
vec4!(mat.column(2), 0.),
vec4!(pos.to_vec(), 1.),
])
}
impl Debug for Node{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_struct("Node")
.field("position", &*self.position)
.field("orientation", &*self.orientation)
.field("scale", &*self.scale)
.field("parent_inv", &self.parent_inv.is_some())
.finish()
}
}
impl Node{
pub fn new(pos: Pnt3, orientation: UnitQuat, scale: Vec3) -> Node{
let local_trafo = trafo_from_parts(&pos, &orientation, &scale);
Node{
position: ValueCache::new(pos),
orientation: ValueCache::new(orientation),
scale: ValueCache::new(scale),
local_transformation: ValueCache::new(local_trafo),
global_transformation: ValueCache::new(local_trafo),
global_scale: ValueCache::new(scale),
parent_inv: None,
}
}
pub fn with_parent(parent: &Node, pos: Pnt3, orientation: UnitQuat, scale: Vec3) -> Node{
let mut node = Node::new(pos, orientation, scale);
node.update_with_parent(Some(parent));
node
}
pub fn identity() -> Node{
Node{
position: ValueCache::new(origin()),
orientation: ValueCache::new(one()),
scale: ValueCache::new(vec3!(1.)),
local_transformation: ValueCache::new(one()),
global_transformation: ValueCache::new(one()),
global_scale: ValueCache::new(vec3!(1.)),
parent_inv: None,
}
}
pub fn identity_with_parent(parent: &Node) -> Node{
let mut node = Node::identity();
*node.global_scale = parent.global_scale();
*node.global_transformation = parent.global_transformation();
node
}
pub fn new_look_at(eye: Pnt3, at: Pnt3, up: Vec3) -> Node{
let rh_dir = eye - at;
let orientation = UnitQuat::new_observer_frame(&rh_dir, &up);
let local_transformation = Isometry3::from_parts(
Translation::from(eye.to_vec()),
orientation
).to_homogeneous();
Node{
position: ValueCache::new(eye),
orientation: ValueCache::new(orientation),
scale: ValueCache::new(vec3!(1.)),
local_transformation: ValueCache::new(local_transformation),
global_transformation: ValueCache::new(local_transformation),
global_scale: ValueCache::new(vec3!(1.)),
parent_inv: None,
}
}
pub fn with_preparent(parent_inv: Mat4, pos: Pnt3, orientation: UnitQuat, scale: Vec3) -> Node{
let mut node = Node::new(pos, orientation, scale);
node.parent_inv = Some(parent_inv);
*node.global_transformation = parent_inv * *node.global_transformation;
node
}
pub fn with_preparent_node(preparent: &Node, pos: Pnt3, orientation: UnitQuat, scale: Vec3) -> Node{
Node::with_preparent(preparent.inv_global_transformation(), pos, orientation, scale)
}
pub fn identity_with_preparent(parent_inv: Mat4) -> Node{
let mut node = Node::identity();
node.parent_inv = Some(parent_inv);
*node.global_transformation = parent_inv;
node
}
pub fn identity_with_preparent_node(preparent: &Node) -> Node{
Node::identity_with_preparent(preparent.inv_global_transformation())
}
pub fn clone_with_preparent(&self, preparent: &Node) -> Node{
let mut node = self.clone();
node.parent_inv = Some(preparent.inv_global_transformation());
node
}
pub fn set_position(&mut self, pos: Pnt3){
*self.position = pos;
}
pub fn position(&self) -> Pnt3{
*self.position
}
pub fn preparent(&self) -> Option<Mat4>{
self.parent_inv
}
pub fn set_angle_axis(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
self.set_orientation(UnitQuat::from_axis_angle(axis, angle.value()));
}
pub fn set_orientation(&mut self, q: UnitQuat){
*self.orientation = q;
}
pub fn orientation(&self) -> UnitQuat{
*self.orientation
}
pub fn rotation(&self) -> Rotation3<f32>{
self.orientation.to_rotation_matrix()
}
pub fn look_at(&mut self, at: &Pnt3, up: &Vec3){
let rh_dir = self.position() - at;
let orientation = UnitQuat::new_observer_frame(&rh_dir, up);
self.set_orientation(orientation);
}
pub fn look_at_node<N: NodeRef>(&mut self, node: &N, up: &Vec3){
let at = node.global_position();
self.look_at(&at, up);
}
pub fn rotate(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
let angle = angle.to_rad().value();
let orientation = UnitQuat::from_axis_angle(axis, angle) * *self.orientation;
self.set_orientation(orientation);
}
pub fn append_orientation(&mut self, rot: &UnitQuat){
let orientation = *rot * *self.orientation;
self.set_orientation(orientation);
}
pub fn translate(&mut self, t: &Vec3){
let position = *self.position + *t;
self.set_position(position);
}
pub fn scale(&self) -> Vec3{
*self.scale
}
pub fn set_scale(&mut self, s: Vec3){
*self.scale = s;
}
pub fn x_axis(&self) -> Unit<Vec3>{
Unit::new_normalize(self.global_transformation().column(0).xyz())
}
pub fn y_axis(&self) -> Unit<Vec3>{
Unit::new_normalize(self.global_transformation().column(1).xyz())
}
pub fn z_axis(&self) -> Unit<Vec3>{
Unit::new_normalize(self.global_transformation().column(2).xyz())
}
pub fn tilt(&mut self, angle: Rad<f32>){
let x_axis = self.x_axis();
self.rotate(angle, &x_axis);
}
pub fn pan(&mut self, angle: Rad<f32>){
let y_axis = self.y_axis();
self.rotate(angle, &y_axis);
}
pub fn roll(&mut self, angle: Rad<f32>){
let z_axis = self.z_axis();
self.rotate(angle, &z_axis);
}
pub fn local_transformation(&self) -> Mat4{
*self.local_transformation
}
pub fn global_transformation(&self) -> Mat4{
*self.global_transformation
}
pub fn global_position(&self) -> Pnt3{
self.global_transformation().column(3).xyz().to_pnt()
}
pub fn global_orientation(&self) -> UnitQuat{
let rot = Mat3::from_columns(&[
normalize(&self.global_transformation().column(0).xyz()),
normalize(&self.global_transformation().column(1).xyz()),
normalize(&self.global_transformation().column(2).xyz()),
]);
UnitQuat::from_rotation_matrix(&Rotation3::from_matrix_unchecked(rot))
}
pub fn global_scale(&self) -> Vec3{
*self.global_scale
}
pub fn inv_local_transformation(&self) -> Mat4{
if *self.scale == vec3!(1.){
return self.local_transformation.fast_orthonormal_inverse();
}
let gs = self.global_scale();
if gs.x == 0. || gs.y == 0. || gs.z == 0.{
*self.local_transformation
}else{
self.local_transformation.fast_affine_inverse().unwrap()
}
}
pub fn inv_global_transformation(&self) -> Mat4{
let gs = self.global_scale();
if gs.x == 0. || gs.y == 0. || gs.z == 0.{
self.global_transformation()
}else if let Some(_parent_inv) = self.parent_inv{
self.global_transformation().fast_affine_inverse().unwrap()
}else{
if *self.global_scale == vec3!(1.){
self.global_transformation().fast_orthonormal_inverse()
}else{
self.global_transformation().fast_affine_inverse().unwrap()
}
}
}
pub fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent_flags(parent, Flags::empty())
}
pub fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: Flags) -> bool{
let changed = self.position.has_changed() ||
self.orientation.has_changed() ||
self.scale.has_changed();
if changed {
*self.local_transformation = trafo_from_parts(&self.position(),
&self.orientation(),
&self.scale());
}
self.global_scale.update();
self.global_transformation.update();
let global_changed = self.local_transformation.has_changed() ||
parent.map(|parent| parent.global_transformation.has_changed())
.unwrap_or(false);
if global_changed {
if let Some(parent) = parent{
let parent_trafo = if flags.is_empty() {
parent.global_transformation()
}else{
let parent_scale = if flags.contains(Flags::NO_SCALE_FROM_PARENT) {
let parent_scale = parent.scale();
let parent_inv_scale = vec3(1. / parent_scale.x, 1./ parent_scale.y, 1. / parent.scale.z);
parent.global_scale().component_mul(&parent_inv_scale)
} else {
parent.global_scale()
};
let parent_orientation = if flags.contains(Flags::NO_ROTATION_FROM_PARENT) {
parent.global_orientation() * inverse(&parent.orientation())
} else {
parent.global_orientation()
};
let parent_position = if flags.contains(Flags::NO_TRANSLATION_FROM_PARENT) {
(parent.global_position() - parent.position()).to_pnt()
} else {
parent.global_position()
};
trafo_from_parts(&parent_position, &parent_orientation, &parent_scale)
};
let parent_trafo = if let Some(parent_inv) = self.parent_inv{
parent_trafo
.fast_mul(&parent_inv)
}else{
parent_trafo
};
*self.global_transformation = parent_trafo
.fast_mul(&*self.local_transformation);
let p = parent.global_scale();
let s = *self.scale;
*self.global_scale = vec3(p.x * s.x, p.y * s.y, p.z * s.z);
}else{
*self.global_transformation = self.local_transformation();
*self.global_scale = *self.scale;
}
}
self.position.update();
self.orientation.update();
self.scale.update();
self.local_transformation.update();
changed || global_changed
}
}
pub trait NodeRef{
fn node(&self) -> &Node;
fn position(&self) -> Pnt3{
self.node().position()
}
fn orientation(&self) -> UnitQuat{
self.node().orientation()
}
fn rotation(&self) -> Rotation3<f32>{
self.node().rotation()
}
fn scale(&self) -> Vec3{
self.node().scale()
}
fn x_axis(&self) -> Unit<Vec3>{
self.node().x_axis()
}
fn y_axis(&self) -> Unit<Vec3>{
self.node().y_axis()
}
fn z_axis(&self) -> Unit<Vec3>{
self.node().z_axis()
}
fn local_transformation(&self) -> Mat4{
self.node().local_transformation()
}
fn global_transformation(&self) -> Mat4{
self.node().global_transformation()
}
fn global_position(&self) -> Pnt3{
self.node().global_position()
}
fn global_orientation(&self) -> UnitQuat{
self.node().global_orientation()
}
fn global_scale(&self) -> Vec3{
self.node().global_scale()
}
fn inv_local_transformation(&self) -> Mat4{
self.node().inv_local_transformation()
}
fn inv_global_transformation(&self) -> Mat4{
self.node().inv_global_transformation()
}
}
pub trait NodeMut{
fn node_mut(&mut self) -> &mut Node;
fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: Flags) -> bool;
fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent_flags(parent, Flags::empty())
}
fn look_at(&mut self, at: &Pnt3, up: &Vec3){
self.node_mut().look_at(at, up);
}
fn rotate(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
self.node_mut().rotate(angle, axis);
}
fn append_orientation(&mut self, rot: &UnitQuat){
self.node_mut().append_orientation(rot);
}
fn tilt(&mut self, angle: Rad<f32>){
self.node_mut().tilt(angle);
}
fn pan(&mut self, angle: Rad<f32>){
self.node_mut().pan(angle);
}
fn roll(&mut self, angle: Rad<f32>){
self.node_mut().roll(angle);
}
fn set_scale(&mut self, s: Vec3){
self.node_mut().set_scale(s);
}
fn translate(&mut self, t: &Vec3){
self.node_mut().translate(t);
}
fn set_position(&mut self, pos: Pnt3){
self.node_mut().set_position(pos);
}
fn set_angle_axis(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
self.node_mut().set_angle_axis(angle, axis);
}
fn set_orientation(&mut self, q: UnitQuat){
self.node_mut().set_orientation(q);
}
}
impl NodeRef for Node{
fn node(&self) -> &Node{
self
}
}
impl NodeMut for Node{
fn node_mut(&mut self) -> &mut Node{
self
}
fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent(parent)
}
fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: Flags) -> bool{
self.update_with_parent_flags(parent, flags)
}
}
impl Mul<Node> for Node{
type Output = Node;
fn mul(self, right: Node) -> Node{
let mut ret = right.clone();
ret.update_with_parent(Some(&self));
ret
}
}
impl Identity<Multiplicative> for Node{
fn identity() -> Node{
Node::identity()
}
}
impl From<Pnt3> for Node{
fn from(pos: Pnt3) -> Node{
Node::new(pos, one(), vec3!(1.))
}
}
impl From<Translation3<f32>> for Node{
fn from(t: Translation3<f32>) -> Node{
Node::new(t.vector.to_pnt(), one(), vec3!(1.))
}
}
impl From<Rotation3<f32>> for Node{
fn from(r: Rotation3<f32>) -> Node{
Node::new(origin(), UnitQuat::from_rotation_matrix(&r), vec3!(1.))
}
}
impl From<Isometry3<f32>> for Node{
fn from(i: Isometry3<f32>) -> Node{
Node::new(i.translation.vector.to_pnt(), i.rotation, vec3!(1.))
}
}
impl From<UnitQuaternion<f32>> for Node{
fn from(q: UnitQuaternion<f32>) -> Node{
Node::new(origin(), q, vec3!(1.))
}
}