diff --git a/geometry/src/rect.rs b/geometry/src/rect.rs index 106a2191..cbe3eec9 100644 --- a/geometry/src/rect.rs +++ b/geometry/src/rect.rs @@ -27,56 +27,90 @@ impl RectF { RectF(origin.0.concat_xy_xy(lower_right.0)) } + // Accessors + #[inline] - pub fn origin(&self) -> Vector2F { + pub fn origin(self) -> Vector2F { Vector2F(self.0.xy()) } #[inline] - pub fn size(&self) -> Vector2F { + pub fn size(self) -> Vector2F { Vector2F(self.0.zw() - self.0.xy()) } #[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()) } #[inline] - pub fn lower_left(&self) -> Vector2F { + pub fn lower_left(self) -> Vector2F { Vector2F(self.0.xw()) } #[inline] - pub fn lower_right(&self) -> Vector2F { + pub fn lower_right(self) -> Vector2F { Vector2F(self.0.zw()) } + // Mutators + #[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 let point = point.0.to_f32x4(); self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true() } #[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.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).all_true() } #[inline] - pub fn is_empty(&self) -> bool { + pub fn is_empty(self) -> bool { self.origin() == self.lower_right() } #[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)) } #[inline] - pub fn union_rect(&self, other: RectF) -> RectF { + pub fn union_rect(self, other: RectF) -> RectF { RectF::from_points( self.origin().min(other.origin()), self.lower_right().max(other.lower_right()), @@ -84,13 +118,13 @@ impl RectF { } #[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.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true() } #[inline] - pub fn intersection(&self, other: RectF) -> Option { + pub fn intersection(self, other: RectF) -> Option { if !self.intersects(other) { None } else { @@ -131,6 +165,12 @@ impl RectF { 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] pub fn round_out(self) -> RectF { 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)] pub struct RectI(pub I32x4); @@ -161,6 +202,8 @@ impl RectI { RectI(origin.0.concat_xy_xy(lower_right.0)) } + // Accessors + #[inline] pub fn origin(&self) -> Vector2I { Vector2I(self.0.xy()) @@ -171,6 +214,26 @@ impl RectI { 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] pub fn upper_right(&self) -> Vector2I { Vector2I(self.0.zy()) @@ -216,6 +279,24 @@ impl RectI { 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 { + if !self.intersects(other) { + None + } else { + Some(RectI::from_points( + self.origin().max(other.origin()), + self.lower_right().min(other.lower_right()), + )) + } + } + #[inline] pub fn contains_point(&self, point: Vector2I) -> bool { // self.origin <= point && point <= self.lower_right - 1 diff --git a/geometry/src/vector.rs b/geometry/src/vector.rs index a848e87c..88b10faa 100644 --- a/geometry/src/vector.rs +++ b/geometry/src/vector.rs @@ -104,6 +104,12 @@ impl Vector2F { 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. #[inline] pub fn square_length(self) -> f32 { @@ -219,6 +225,16 @@ impl Vector2I { 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] pub fn scale(self, factor: i32) -> Vector2I { Vector2I(self.0 * I32x2::splat(factor)) @@ -250,6 +266,14 @@ impl AddAssign for Vector2I { } } +impl Neg for Vector2I { + type Output = Vector2I; + #[inline] + fn neg(self) -> Vector2I { + Vector2I(-self.0) + } +} + impl Sub for Vector2I { type Output = Vector2I; #[inline] diff --git a/simd/src/arm/mod.rs b/simd/src/arm/mod.rs index a8503d56..8b2dc01f 100644 --- a/simd/src/arm/mod.rs +++ b/simd/src/arm/mod.rs @@ -510,6 +510,13 @@ impl I32x4 { 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] pub fn min(self, other: I32x4) -> I32x4 { unsafe { I32x4(simd_fmin(self.0, other.0)) } @@ -527,6 +534,11 @@ impl I32x4 { 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 #[inline] @@ -534,6 +546,11 @@ impl I32x4 { 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 #[inline] diff --git a/simd/src/extras.rs b/simd/src/extras.rs index 1e247e4f..c53bbdfa 100644 --- a/simd/src/extras.rs +++ b/simd/src/extras.rs @@ -206,6 +206,30 @@ impl Neg for I32x2 { // 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 { #[inline] fn add_assign(&mut self, other: I32x4) { diff --git a/simd/src/scalar/mod.rs b/simd/src/scalar/mod.rs index e2a4a646..1e6bab84 100644 --- a/simd/src/scalar/mod.rs +++ b/simd/src/scalar/mod.rs @@ -522,7 +522,8 @@ impl I32x4 { I32x4([x; 4]) } - #[inline] + // Basic operations + #[inline] pub fn min(self, other: 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 #[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] pub fn packed_le(self, other: I32x4) -> U32x4 { U32x4([ @@ -562,6 +583,11 @@ impl I32x4 { 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 #[inline] diff --git a/simd/src/test.rs b/simd/src/test.rs index 317aeb2e..629127cc 100644 --- a/simd/src/test.rs +++ b/simd/src/test.rs @@ -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.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.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); 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.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.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)); } diff --git a/simd/src/x86/mod.rs b/simd/src/x86/mod.rs index 086358c6..91f9eb20 100644 --- a/simd/src/x86/mod.rs +++ b/simd/src/x86/mod.rs @@ -492,6 +492,11 @@ impl I32x2 { // Basic operations + #[inline] + pub fn max(self, other: I32x2) -> I32x2 { + self.to_i32x4().max(other.to_i32x4()).xy() + } + #[inline] pub fn min(self, other: I32x2) -> I32x2 { 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 /// Converts these packed integers to floats. @@ -657,6 +672,11 @@ impl I32x4 { // Basic operations + #[inline] + pub fn max(self, other: I32x4) -> I32x4 { + unsafe { I32x4(x86::_mm_max_epi32(self.0, other.0)) } + } + #[inline] pub fn min(self, other: I32x4) -> I32x4 { 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)) } } + #[inline] + pub fn packed_lt(self, other: I32x4) -> U32x4 { + other.packed_gt(self) + } + #[inline] pub fn packed_le(self, other: I32x4) -> U32x4 { !self.packed_gt(other)