Skip to content

Commit

Permalink
Add snapped to integer vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
joriskleiber committed Jun 26, 2024
1 parent e25e994 commit 8e5e481
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 25 deletions.
2 changes: 2 additions & 0 deletions godot-core/src/builtin/vectors/vector2i.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ impl_vector_fns!(Vector2i, glam::IVec2, i32, (x, y));
impl_vector2x_fns!(Vector2i, i32);

impl Vector2i {
impl_integer_vector_fns!(x, y);

/// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be truncated.
#[inline]
pub const fn from_vector2(v: Vector2) -> Self {
Expand Down
2 changes: 2 additions & 0 deletions godot-core/src/builtin/vectors/vector3i.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ impl_vector_fns!(Vector3i, glam::IVec3, i32, (x, y, z));
impl_vector3x_fns!(Vector3i, i32);

impl Vector3i {
impl_integer_vector_fns!(x, y, z);

/// Constructs a new `Vector3i` from a [`Vector3`]. The floating point coordinates will be truncated.
#[inline]
pub const fn from_vector3(v: Vector3) -> Self {
Expand Down
2 changes: 2 additions & 0 deletions godot-core/src/builtin/vectors/vector4i.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ impl_vector_fns!(Vector4i, glam::IVec4, i32, (x, y, z, w));
impl_vector4x_fns!(Vector4i, i32);

impl Vector4i {
impl_integer_vector_fns!(x, y, z, w);

/// Constructs a new `Vector4i` from a [`Vector4`]. The floating point coordinates will be
/// truncated.
#[inline]
Expand Down
46 changes: 45 additions & 1 deletion godot-core/src/builtin/vectors/vector_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,51 @@ macro_rules! impl_vector_fns {
}
}

pub(super) fn snap_one(mut value: i32, step: i32) -> i32 {
assert!(
value != i32::MIN || step != -1,
"snapped() called on vector component i32::MIN with step component -1"
);

if step != 0 {
let a = value + step / 2;

// manual implement `a.div_floor(step)` since Rust's native method is still unstable, as of 1.79.0
let mut d = a / step;
let r = a % step;
if (r > 0 && step < 0) || (r < 0 && step > 0) {
d -= 1;
}

value = step * d;
}

value
}

/// Implements functions that are present only on integer vectors.
macro_rules! impl_integer_vector_fns {
(
// Names of the components, for example `x, y`.
$($comp:ident),*
) => {
/// A new vector with each component snapped to the closest multiple of the corresponding
/// component in `step`.
///
/// # Panics
/// If any component of `self` is `i32::MIN` while the same component on `step` is `-1`.
pub fn snapped(self, step: Self) -> Self {
use crate::builtin::vectors::vector_macros::snap_one;

Self::new(
$(
snap_one(self.$comp, step.$comp)
),*
)
}
};
}

/// Implements functions that are present only on floating-point vectors.
macro_rules! impl_float_vector_fns {
(
Expand Down Expand Up @@ -612,7 +657,6 @@ macro_rules! impl_float_vector_fns {

/// A new vector with each component snapped to the closest multiple of the corresponding
/// component in `step`.
// TODO: also implement for integer vectors
#[inline]
pub fn snapped(self, step: Self) -> Self {
Self::new(
Expand Down
18 changes: 10 additions & 8 deletions itest/rust/src/builtin_tests/geometry/vector_test/vector2i_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ fn sign() {
assert_eq!(b.sign(), b.as_inner().sign());
}

// TODO: implement snapped for integer vectors
// #[itest]
// fn snapped() {
// let a = Vector2i::new(12, 34);
// let b = Vector2i::new(5, -5);

// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
// }
#[itest]
fn snapped() {
let a = Vector2i::new(12, 34);
let b = Vector2i::new(5, -5);
let c = Vector2i::new(0, 0);
let d = Vector2i::new(3, 0);

assert_eq!(a.snapped(b), a.as_inner().snapped(b));
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
}
18 changes: 10 additions & 8 deletions itest/rust/src/builtin_tests/geometry/vector_test/vector3i_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,13 @@ fn sign() {
assert_eq!(b.sign(), b.as_inner().sign());
}

// TODO: implement snapped for integer vectors
// #[itest]
// fn snapped() {
// let a = Vector3i::new(12, 34, 56);
// let b = Vector3i::new(5, -5, 6);

// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
// }
#[itest]
fn snapped() {
let a = Vector3i::new(12, 34, -56);
let b = Vector3i::new(5, -5, 6);
let c = Vector3i::new(0, 3, 0);
let d = Vector3i::new(3, 0, 0);

assert_eq!(a.snapped(b), a.as_inner().snapped(b));
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
}
18 changes: 10 additions & 8 deletions itest/rust/src/builtin_tests/geometry/vector_test/vector4i_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@ fn sign() {
assert_eq!(b.sign(), b.as_inner().sign());
}

// TODO: implement snapped for integer vectors
// #[itest]
// fn snapped() {
// let a = Vector4i::new(12, 34, 56, 78);
// let b = Vector4i::new(5, -5, 6, -6);

// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
// }
#[itest]
fn snapped() {
let a = Vector4i::new(12, 34, 56, -78);
let b = Vector4i::new(5, -5, 6, 6);
let c = Vector4i::new(0, 3, 0, 0);
let d = Vector4i::new(3, 0, -3, 0);

assert_eq!(a.snapped(b), a.as_inner().snapped(b));
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
}

0 comments on commit 8e5e481

Please sign in to comment.