Skip to content

Commit d444540

Browse files
committed
Add snapped to integer vectors
1 parent cd31a83 commit d444540

File tree

7 files changed

+81
-25
lines changed

7 files changed

+81
-25
lines changed

godot-core/src/builtin/vectors/vector2i.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ impl_vector_fns!(Vector2i, glam::IVec2, i32, (x, y));
4444
impl_vector2x_fns!(Vector2i, i32);
4545

4646
impl Vector2i {
47+
impl_integer_vector_fns!(x, y);
48+
4749
/// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be truncated.
4850
#[inline]
4951
pub const fn from_vector2(v: Vector2) -> Self {

godot-core/src/builtin/vectors/vector3i.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ impl_vector_fns!(Vector3i, glam::IVec3, i32, (x, y, z));
4747
impl_vector3x_fns!(Vector3i, i32);
4848

4949
impl Vector3i {
50+
impl_integer_vector_fns!(x, y, z);
51+
5052
/// Constructs a new `Vector3i` from a [`Vector3`]. The floating point coordinates will be truncated.
5153
#[inline]
5254
pub const fn from_vector3(v: Vector3) -> Self {

godot-core/src/builtin/vectors/vector4i.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ impl_vector_fns!(Vector4i, glam::IVec4, i32, (x, y, z, w));
4848
impl_vector4x_fns!(Vector4i, i32);
4949

5050
impl Vector4i {
51+
impl_integer_vector_fns!(x, y, z, w);
52+
5153
/// Constructs a new `Vector4i` from a [`Vector4`]. The floating point coordinates will be
5254
/// truncated.
5355
#[inline]

godot-core/src/builtin/vectors/vector_macros.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,51 @@ macro_rules! impl_vector_fns {
457457
}
458458
}
459459

460+
pub(super) fn snap_one(mut value: i32, step: i32) -> i32 {
461+
assert!(
462+
value != i32::MIN || step != -1,
463+
"snapped() called on vector component i32::MIN with step component -1"
464+
);
465+
466+
if step != 0 {
467+
let a = value + step / 2;
468+
469+
// manual implement `a.div_floor(step)` since Rust's native method is still unstable, as of 1.79.0
470+
let mut d = a / step;
471+
let r = a % step;
472+
if (r > 0 && step < 0) || (r < 0 && step > 0) {
473+
d -= 1;
474+
}
475+
476+
value = step * d;
477+
}
478+
479+
value
480+
}
481+
482+
/// Implements functions that are present only on integer vectors.
483+
macro_rules! impl_integer_vector_fns {
484+
(
485+
// Names of the components, for example `x, y`.
486+
$($comp:ident),*
487+
) => {
488+
/// A new vector with each component snapped to the closest multiple of the corresponding
489+
/// component in `step`.
490+
///
491+
/// # Panics
492+
/// If any component of `self` is `i32::MIN` while the same component on `step` is `-1`.
493+
pub fn snapped(self, step: Self) -> Self {
494+
use crate::builtin::vectors::vector_macros::snap_one;
495+
496+
Self::new(
497+
$(
498+
snap_one(self.$comp, step.$comp)
499+
),*
500+
)
501+
}
502+
};
503+
}
504+
460505
/// Implements functions that are present only on floating-point vectors.
461506
macro_rules! impl_float_vector_fns {
462507
(
@@ -612,7 +657,6 @@ macro_rules! impl_float_vector_fns {
612657

613658
/// A new vector with each component snapped to the closest multiple of the corresponding
614659
/// component in `step`.
615-
// TODO: also implement for integer vectors
616660
#[inline]
617661
pub fn snapped(self, step: Self) -> Self {
618662
Self::new(

itest/rust/src/builtin_tests/geometry/vector_test/vector2i_test.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ fn sign() {
102102
assert_eq!(b.sign(), b.as_inner().sign());
103103
}
104104

105-
// TODO: implement snapped for integer vectors
106-
// #[itest]
107-
// fn snapped() {
108-
// let a = Vector2i::new(12, 34);
109-
// let b = Vector2i::new(5, -5);
110-
111-
// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
112-
// }
105+
#[itest]
106+
fn snapped() {
107+
let a = Vector2i::new(12, 34);
108+
let b = Vector2i::new(5, -5);
109+
let c = Vector2i::new(0, 0);
110+
let d = Vector2i::new(3, 0);
111+
112+
assert_eq!(a.snapped(b), a.as_inner().snapped(b));
113+
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
114+
}

itest/rust/src/builtin_tests/geometry/vector_test/vector3i_test.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ fn sign() {
9999
assert_eq!(b.sign(), b.as_inner().sign());
100100
}
101101

102-
// TODO: implement snapped for integer vectors
103-
// #[itest]
104-
// fn snapped() {
105-
// let a = Vector3i::new(12, 34, 56);
106-
// let b = Vector3i::new(5, -5, 6);
107-
108-
// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
109-
// }
102+
#[itest]
103+
fn snapped() {
104+
let a = Vector3i::new(12, 34, -56);
105+
let b = Vector3i::new(5, -5, 6);
106+
let c = Vector3i::new(0, 3, 0);
107+
let d = Vector3i::new(3, 0, 0);
108+
109+
assert_eq!(a.snapped(b), a.as_inner().snapped(b));
110+
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
111+
}

itest/rust/src/builtin_tests/geometry/vector_test/vector4i_test.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,13 @@ fn sign() {
103103
assert_eq!(b.sign(), b.as_inner().sign());
104104
}
105105

106-
// TODO: implement snapped for integer vectors
107-
// #[itest]
108-
// fn snapped() {
109-
// let a = Vector4i::new(12, 34, 56, 78);
110-
// let b = Vector4i::new(5, -5, 6, -6);
111-
112-
// assert_eq!(a.snapped(b), a.as_inner().snapped(b));
113-
// }
106+
#[itest]
107+
fn snapped() {
108+
let a = Vector4i::new(12, 34, 56, -78);
109+
let b = Vector4i::new(5, -5, 6, 6);
110+
let c = Vector4i::new(0, 3, 0, 0);
111+
let d = Vector4i::new(3, 0, -3, 0);
112+
113+
assert_eq!(a.snapped(b), a.as_inner().snapped(b));
114+
assert_eq!(c.snapped(d), c.as_inner().snapped(d));
115+
}

0 commit comments

Comments
 (0)