Add a few missing methods to geometry and SIMD; fix SIMD tests

This commit is contained in:
Patrick Walton 2020-01-14 21:31:22 -08:00
parent 422ccbc15c
commit 3f72847294
7 changed files with 212 additions and 15 deletions

View File

@ -27,56 +27,90 @@ impl RectF {
RectF(origin.0.concat_xy_xy(lower_right.0)) RectF(origin.0.concat_xy_xy(lower_right.0))
} }
// Accessors
#[inline] #[inline]
pub fn origin(&self) -> Vector2F { pub fn origin(self) -> Vector2F {
Vector2F(self.0.xy()) Vector2F(self.0.xy())
} }
#[inline] #[inline]
pub fn size(&self) -> Vector2F { pub fn size(self) -> Vector2F {
Vector2F(self.0.zw() - self.0.xy()) Vector2F(self.0.zw() - self.0.xy())
} }
#[inline] #[inline]
pub fn upper_right(&self) -> Vector2F { pub fn origin_x(self) -> f32 {
self.0.x()
}
#[inline]
pub fn origin_y(self) -> f32 {
self.0.y()
}
#[inline]
pub fn width(self) -> f32 {
self.0.z() - self.0.x()
}
#[inline]
pub fn height(self) -> f32 {
self.0.w() - self.0.y()
}
#[inline]
pub fn upper_right(self) -> Vector2F {
Vector2F(self.0.zy()) Vector2F(self.0.zy())
} }
#[inline] #[inline]
pub fn lower_left(&self) -> Vector2F { pub fn lower_left(self) -> Vector2F {
Vector2F(self.0.xw()) Vector2F(self.0.xw())
} }
#[inline] #[inline]
pub fn lower_right(&self) -> Vector2F { pub fn lower_right(self) -> Vector2F {
Vector2F(self.0.zw()) Vector2F(self.0.zw())
} }
// Mutators
#[inline] #[inline]
pub fn contains_point(&self, point: Vector2F) -> bool { pub fn set_origin_x(&mut self, x: f32) {
self.0.set_x(x)
}
#[inline]
pub fn set_origin_y(&mut self, y: f32) {
self.0.set_y(y)
}
#[inline]
pub fn contains_point(self, point: Vector2F) -> bool {
// self.origin <= point && point <= self.lower_right // self.origin <= point && point <= self.lower_right
let point = point.0.to_f32x4(); let point = point.0.to_f32x4();
self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true() self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true()
} }
#[inline] #[inline]
pub fn contains_rect(&self, other: RectF) -> bool { pub fn contains_rect(self, other: RectF) -> bool {
// self.origin <= other.origin && other.lower_right <= self.lower_right // self.origin <= other.origin && other.lower_right <= self.lower_right
self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).all_true() self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).all_true()
} }
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(self) -> bool {
self.origin() == self.lower_right() self.origin() == self.lower_right()
} }
#[inline] #[inline]
pub fn union_point(&self, point: Vector2F) -> RectF { pub fn union_point(self, point: Vector2F) -> RectF {
RectF::from_points(self.origin().min(point), self.lower_right().max(point)) RectF::from_points(self.origin().min(point), self.lower_right().max(point))
} }
#[inline] #[inline]
pub fn union_rect(&self, other: RectF) -> RectF { pub fn union_rect(self, other: RectF) -> RectF {
RectF::from_points( RectF::from_points(
self.origin().min(other.origin()), self.origin().min(other.origin()),
self.lower_right().max(other.lower_right()), self.lower_right().max(other.lower_right()),
@ -84,13 +118,13 @@ impl RectF {
} }
#[inline] #[inline]
pub fn intersects(&self, other: RectF) -> bool { pub fn intersects(self, other: RectF) -> bool {
// self.origin < other.lower_right && other.origin < self.lower_right // self.origin < other.lower_right && other.origin < self.lower_right
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true() self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
} }
#[inline] #[inline]
pub fn intersection(&self, other: RectF) -> Option<RectF> { pub fn intersection(self, other: RectF) -> Option<RectF> {
if !self.intersects(other) { if !self.intersects(other) {
None None
} else { } else {
@ -131,6 +165,12 @@ impl RectF {
RectF(self.0 * factors.0.concat_xy_xy(factors.0)) RectF(self.0 * factors.0.concat_xy_xy(factors.0))
} }
/// Rounds all points to the nearest integer.
#[inline]
pub fn round(self) -> RectF {
RectF(self.0.to_i32x4().to_f32x4())
}
#[inline] #[inline]
pub fn round_out(self) -> RectF { pub fn round_out(self) -> RectF {
RectF::from_points(self.origin().floor(), self.lower_right().ceil()) RectF::from_points(self.origin().floor(), self.lower_right().ceil())
@ -147,6 +187,7 @@ impl RectF {
} }
} }
/// NB: The origin is inclusive, while the lower right point is exclusive.
#[derive(Clone, Copy, Debug, PartialEq, Default)] #[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct RectI(pub I32x4); pub struct RectI(pub I32x4);
@ -161,6 +202,8 @@ impl RectI {
RectI(origin.0.concat_xy_xy(lower_right.0)) RectI(origin.0.concat_xy_xy(lower_right.0))
} }
// Accessors
#[inline] #[inline]
pub fn origin(&self) -> Vector2I { pub fn origin(&self) -> Vector2I {
Vector2I(self.0.xy()) Vector2I(self.0.xy())
@ -171,6 +214,26 @@ impl RectI {
Vector2I(self.0.zw() - self.0.xy()) Vector2I(self.0.zw() - self.0.xy())
} }
#[inline]
pub fn origin_x(self) -> i32 {
self.0.x()
}
#[inline]
pub fn origin_y(self) -> i32 {
self.0.y()
}
#[inline]
pub fn width(self) -> i32 {
self.0.z() - self.0.x()
}
#[inline]
pub fn height(self) -> i32 {
self.0.w() - self.0.y()
}
#[inline] #[inline]
pub fn upper_right(&self) -> Vector2I { pub fn upper_right(&self) -> Vector2I {
Vector2I(self.0.zy()) Vector2I(self.0.zy())
@ -216,6 +279,24 @@ impl RectI {
self.0[3] self.0[3]
} }
#[inline]
pub fn intersects(self, other: RectI) -> bool {
// self.origin < other.lower_right && other.origin < self.lower_right
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
}
#[inline]
pub fn intersection(self, other: RectI) -> Option<RectI> {
if !self.intersects(other) {
None
} else {
Some(RectI::from_points(
self.origin().max(other.origin()),
self.lower_right().min(other.lower_right()),
))
}
}
#[inline] #[inline]
pub fn contains_point(&self, point: Vector2I) -> bool { pub fn contains_point(&self, point: Vector2I) -> bool {
// self.origin <= point && point <= self.lower_right - 1 // self.origin <= point && point <= self.lower_right - 1

View File

@ -104,6 +104,12 @@ impl Vector2F {
Vector2F(self.0.ceil()) Vector2F(self.0.ceil())
} }
/// Rounds both coordinates to the nearest integer.
#[inline]
pub fn round(self) -> Vector2F {
Vector2F(self.0.to_i32x2().to_f32x2())
}
/// Treats this point as a vector and calculates its squared length. /// Treats this point as a vector and calculates its squared length.
#[inline] #[inline]
pub fn square_length(self) -> f32 { pub fn square_length(self) -> f32 {
@ -219,6 +225,16 @@ impl Vector2I {
self.0[1] = y; self.0[1] = y;
} }
#[inline]
pub fn min(self, other: Vector2I) -> Vector2I {
Vector2I(self.0.min(other.0))
}
#[inline]
pub fn max(self, other: Vector2I) -> Vector2I {
Vector2I(self.0.max(other.0))
}
#[inline] #[inline]
pub fn scale(self, factor: i32) -> Vector2I { pub fn scale(self, factor: i32) -> Vector2I {
Vector2I(self.0 * I32x2::splat(factor)) Vector2I(self.0 * I32x2::splat(factor))
@ -250,6 +266,14 @@ impl AddAssign<Vector2I> for Vector2I {
} }
} }
impl Neg for Vector2I {
type Output = Vector2I;
#[inline]
fn neg(self) -> Vector2I {
Vector2I(-self.0)
}
}
impl Sub<Vector2I> for Vector2I { impl Sub<Vector2I> for Vector2I {
type Output = Vector2I; type Output = Vector2I;
#[inline] #[inline]

View File

@ -510,6 +510,13 @@ impl I32x4 {
I32x4::new(x, x, x, x) I32x4::new(x, x, x, x)
} }
// Basic operations
#[inline]
pub fn max(self, other: I32x4) -> I32x4 {
unsafe { I32x4(simd_fmax(self.0, other.0)) }
}
#[inline] #[inline]
pub fn min(self, other: I32x4) -> I32x4 { pub fn min(self, other: I32x4) -> I32x4 {
unsafe { I32x4(simd_fmin(self.0, other.0)) } unsafe { I32x4(simd_fmin(self.0, other.0)) }
@ -527,6 +534,11 @@ impl I32x4 {
unsafe { U32x4(simd_le(self.0, other.0)) } unsafe { U32x4(simd_le(self.0, other.0)) }
} }
#[inline]
pub fn packed_lt(self, other: I32x4) -> U32x4 {
unsafe { U32x4(simd_lt(self.0, other.0)) }
}
// Concatenations // Concatenations
#[inline] #[inline]
@ -534,6 +546,11 @@ impl I32x4 {
unsafe { I32x4(simd_shuffle4(self.0, other.0, [0, 1, 4, 5])) } unsafe { I32x4(simd_shuffle4(self.0, other.0, [0, 1, 4, 5])) }
} }
#[inline]
pub fn concat_zw_zw(self, other: I32x4) -> I32x4 {
unsafe { I32x4(simd_shuffle4(self.0, other.0, [2, 3, 6, 7])) }
}
// Swizzle conversions // Swizzle conversions
#[inline] #[inline]

View File

@ -206,6 +206,30 @@ impl Neg for I32x2 {
// Four 32-bit integers // Four 32-bit integers
impl I32x4 {
// Accessors
#[inline]
pub fn x(self) -> i32 {
self[0]
}
#[inline]
pub fn y(self) -> i32 {
self[1]
}
#[inline]
pub fn z(self) -> i32 {
self[2]
}
#[inline]
pub fn w(self) -> i32 {
self[3]
}
}
impl AddAssign for I32x4 { impl AddAssign for I32x4 {
#[inline] #[inline]
fn add_assign(&mut self, other: I32x4) { fn add_assign(&mut self, other: I32x4) {

View File

@ -522,7 +522,8 @@ impl I32x4 {
I32x4([x; 4]) I32x4([x; 4])
} }
#[inline] // Basic operations
#[inline] #[inline]
pub fn min(self, other: I32x4) -> I32x4 { pub fn min(self, other: I32x4) -> I32x4 {
I32x4([ I32x4([
@ -533,6 +534,16 @@ impl I32x4 {
]) ])
} }
#[inline]
pub fn max(self, other: I32x4) -> I32x4 {
I32x4([
self[0].max(other[0]),
self[1].max(other[1]),
self[2].max(other[2]),
self[3].max(other[3]),
])
}
// Packed comparisons // Packed comparisons
#[inline] #[inline]
@ -545,6 +556,16 @@ impl I32x4 {
]) ])
} }
#[inline]
pub fn packed_gt(self, other: I32x4) -> U32x4 {
U32x4([
if self[0] > other[0] { !0 } else { 0 },
if self[1] > other[1] { !0 } else { 0 },
if self[2] > other[2] { !0 } else { 0 },
if self[3] > other[3] { !0 } else { 0 },
])
}
#[inline] #[inline]
pub fn packed_le(self, other: I32x4) -> U32x4 { pub fn packed_le(self, other: I32x4) -> U32x4 {
U32x4([ U32x4([
@ -562,6 +583,11 @@ impl I32x4 {
I32x4([self[0], self[1], other[0], other[1]]) I32x4([self[0], self[1], other[0], other[1]])
} }
#[inline]
pub fn concat_zw_zw(self, other: I32x4) -> I32x4 {
I32x4([self[2], self[3], other[2], other[3]])
}
// Swizzle conversions // Swizzle conversions
#[inline] #[inline]

View File

@ -45,7 +45,7 @@ fn test_f32x4_basic_ops() {
assert_eq!(c.abs(), F32x4::new(1.0, 1.3, 20.0, 3.6)); assert_eq!(c.abs(), F32x4::new(1.0, 1.3, 20.0, 3.6));
assert_eq!(c.floor(), F32x4::new(-1.0, 1.0, -20.0, 3.0)); assert_eq!(c.floor(), F32x4::new(-1.0, 1.0, -20.0, 3.0));
assert_eq!(c.ceil(), F32x4::new(-1.0, 2.0, -20.0, 4.0)); assert_eq!(c.ceil(), F32x4::new(-1.0, 2.0, -20.0, 4.0));
assert_eq!(c.round(), F32x4::new(-1.0, 1.0, -20.0, 4.0)); assert_eq!(c.to_i32x4().to_f32x4(), F32x4::new(-1.0, 1.0, -20.0, 4.0));
let d = F32x4::new(1.0, 2.0, 3.0, 4.0); let d = F32x4::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(d.sqrt(), F32x4::new(1.0, 1.4142135, 1.7320508, 2.0)); assert_eq!(d.sqrt(), F32x4::new(1.0, 1.4142135, 1.7320508, 2.0));
} }
@ -687,5 +687,5 @@ fn test_f32x4s_basic_ops() {
assert_eq!(c.abs(), F32x4S::new(1.0, 1.3, 20.0, 3.6)); assert_eq!(c.abs(), F32x4S::new(1.0, 1.3, 20.0, 3.6));
assert_eq!(c.floor(), F32x4S::new(-1.0, 1.0, -20.0, 3.0)); assert_eq!(c.floor(), F32x4S::new(-1.0, 1.0, -20.0, 3.0));
assert_eq!(c.ceil(), F32x4S::new(-1.0, 2.0, -20.0, 4.0)); assert_eq!(c.ceil(), F32x4S::new(-1.0, 2.0, -20.0, 4.0));
assert_eq!(c.round(), F32x4S::new(-1.0, 1.0, -20.0, 4.0)); assert_eq!(c.to_i32x4().to_f32x4(), F32x4S::new(-1.0, 1.0, -20.0, 4.0));
} }

View File

@ -492,6 +492,11 @@ impl I32x2 {
// Basic operations // Basic operations
#[inline]
pub fn max(self, other: I32x2) -> I32x2 {
self.to_i32x4().max(other.to_i32x4()).xy()
}
#[inline] #[inline]
pub fn min(self, other: I32x2) -> I32x2 { pub fn min(self, other: I32x2) -> I32x2 {
self.to_i32x4().min(other.to_i32x4()).xy() self.to_i32x4().min(other.to_i32x4()).xy()
@ -639,6 +644,16 @@ impl I32x4 {
} }
} }
#[inline]
pub fn concat_zw_zw(self, other: I32x4) -> I32x4 {
unsafe {
let this = x86::_mm_castsi128_pd(self.0);
let other = x86::_mm_castsi128_pd(other.0);
let result = x86::_mm_unpackhi_pd(this, other);
I32x4(x86::_mm_castpd_si128(result))
}
}
// Conversions // Conversions
/// Converts these packed integers to floats. /// Converts these packed integers to floats.
@ -657,6 +672,11 @@ impl I32x4 {
// Basic operations // Basic operations
#[inline]
pub fn max(self, other: I32x4) -> I32x4 {
unsafe { I32x4(x86::_mm_max_epi32(self.0, other.0)) }
}
#[inline] #[inline]
pub fn min(self, other: I32x4) -> I32x4 { pub fn min(self, other: I32x4) -> I32x4 {
unsafe { I32x4(x86::_mm_min_epi32(self.0, other.0)) } unsafe { I32x4(x86::_mm_min_epi32(self.0, other.0)) }
@ -676,6 +696,11 @@ impl I32x4 {
unsafe { U32x4(x86::_mm_cmpgt_epi32(self.0, other.0)) } unsafe { U32x4(x86::_mm_cmpgt_epi32(self.0, other.0)) }
} }
#[inline]
pub fn packed_lt(self, other: I32x4) -> U32x4 {
other.packed_gt(self)
}
#[inline] #[inline]
pub fn packed_le(self, other: I32x4) -> U32x4 { pub fn packed_le(self, other: I32x4) -> U32x4 {
!self.packed_gt(other) !self.packed_gt(other)