Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transform2 type #54

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/mat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3686,6 +3686,16 @@ macro_rules! mat_impl_mat3 {
}
}
}
/// A `Mat3` can be obtained from a `Transform2`, by rotating, then scaling, then
/// translating.
impl<T> From<Transform2<T,T,T>> for Mat3<T>
where T: Real + MulAdd<T,T,Output=T>
{
fn from(xform: Transform2<T,T,T>) -> Self {
let Transform2 { position, orientation, scale } = xform;
Mat3::rotation_z(orientation).scaled_3d(scale).translated_2d(position)
}
}
impl<T> From<Quaternion<T>> for Mat3<T>
where T: Copy + Zero + One + Mul<Output=T> + Add<Output=T> + Sub<Output=T>
{
Expand Down Expand Up @@ -4159,7 +4169,7 @@ pub mod repr_c {
use super::vec::repr_c::{Vec4, Vec4 as CVec4};

use super::quaternion::repr_c::Quaternion;
use super::transform::repr_c::Transform;
use super::transform::repr_c::*;

mat_declare_modules!{}
}
Expand All @@ -4181,7 +4191,7 @@ pub mod repr_simd {
use super::vec::repr_c::{Vec4 as CVec4};

use super::quaternion::repr_simd::Quaternion;
use super::transform::repr_simd::Transform;
use super::transform::repr_simd::*;

mat_declare_modules!{}
}
Expand Down
91 changes: 72 additions & 19 deletions src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,80 @@ macro_rules! transform_complete_mod {
}
}

/// LERP on a `Transform` is defined as LERP-ing between the positions and scales,
/// and performing SLERP between the orientations.
impl<'a,P,O,S,Factor> Lerp<Factor> for &'a Transform<P,O,S>
/// A convenient position + orientation + scale container, backed by two `Vec2`.
///
/// It can be easily interpolated and converted to a `Mat3` of any layout.
///
/// ```
/// # extern crate vek;
/// # #[macro_use] extern crate approx;
/// # use vek::{Transform2, Mat3, Vec2};
/// # fn main() {
/// let (p, rz, s) = (Vec2::unit_x(), 3.0_f32, 5.0_f32);
/// let a = Mat3::rotation_z(rz).scaled_2d(s).translated_2d(p);
/// let b = Mat3::from(Transform2 {
/// position: p,
/// orientation: rz,
/// scale: Vec2::broadcast(s),
/// });
/// assert_relative_eq!(a, b);
/// # }
/// ```
// Name decided by looking at this thread:
// https://www.gamedev.net/forums/topic/611925-is-there-a-name-for-position-orientation/
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, /*Ord, PartialOrd*/)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Transform2<P,O,S> {
/// Local position.
pub position: Vec2<P>,
/// Local orientation around the Z axis; It is not named `rotation` because `rotation` denotes an
/// operation, but not a current state.
pub orientation: O,
/// Local scale.
pub scale: Vec2<S>,
}

/// The default `Transform2` has a zero position, zero orientation and unit scale.
///
/// ```
/// # use vek::{Transform2, Vec2};
/// let a = Transform2 {
/// position: Vec2::<f32>::zero(),
/// orientation: f32::zero(),
/// scale: Vec2::<f32>::one(),
/// };
/// assert_eq!(a, Transform2::default());
/// ```
impl<P: Zero, O: Zero + One, S: One> Default for Transform2<P,O,S> {
fn default() -> Self {
Self {
position: Vec2::zero(),
orientation: O::zero(),
scale: Vec2::one(),
}
}
}

/// LERP on a `Transform2` is defined as LERP-ing between the positions, rotations, and scales.
impl<P,O,S,Factor> Lerp<Factor> for Transform2<P,O,S>
where Factor: Copy + Into<O>,
&'a P: Lerp<Factor,Output=P>,
&'a S: Lerp<Factor,Output=S>,
O: Lerp<O,Output=O> + Real + Add<Output=O>,
P: Lerp<Factor,Output=P>,
S: Lerp<Factor,Output=S>,
O: Lerp<Factor,Output=O> + Real + Add<Output=O>,
{
type Output = Transform<P,O,S>;
fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self::Output {
Transform {
position: Lerp::lerp_unclamped(&a.position, &b.position, t),
orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
scale: Lerp::lerp_unclamped(&a.scale, &b.scale, t),
type Output = Self;
fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self {
Transform2 {
position: Lerp::lerp_unclamped(a.position, b.position, t),
orientation: Lerp::lerp_unclamped(a.orientation, b.orientation, t),
scale: Lerp::lerp_unclamped(a.scale, b.scale, t),
}
}
fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self::Output {
Transform {
position: Lerp::lerp_unclamped_precise(&a.position, &b.position, t),
orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
scale: Lerp::lerp_unclamped_precise(&a.scale, &b.scale, t),
fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self {
Transform2 {
position: Lerp::lerp_unclamped_precise(a.position, b.position, t),
orientation: Lerp::lerp_unclamped_precise(a.orientation, b.orientation, t),
scale: Lerp::lerp_unclamped_precise(a.scale, b.scale, t),
}
}
}
Expand All @@ -122,11 +175,11 @@ macro_rules! transform_complete_mod {

#[cfg(all(nightly, feature="repr_simd"))]
pub mod repr_simd {
//! `Transform` struct that uses `#[repr(simd)]` vectors and quaternions.
//! Transform types that use `#[repr(simd)]` types for their positions, orientations, and scales.
transform_complete_mod!(repr_simd);
}
pub mod repr_c {
//! `Transform` struct that uses `#[repr(C)]` vectors and quaternions.
//! Transform types that use `#[repr(C)]` types for their positions, orientations, and scales.
transform_complete_mod!(repr_c);
}
pub use self::repr_c::*;