Skip to content

Commit 974af2d

Browse files
committed
Add missing integer vector methods
1 parent 3ab6b2a commit 974af2d

File tree

5 files changed

+284
-24
lines changed

5 files changed

+284
-24
lines changed

godot-core/src/builtin/math/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub use approx_eq::ApproxEq;
1313
pub use float::FloatExt;
1414

1515
// Internal glam re-exports
16-
pub(crate) use glam::{IVec2, IVec3, IVec4};
1716
pub(crate) use glam_helpers::*;
1817

1918
#[cfg(test)]

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

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
*/
66

77
use godot_ffi as sys;
8+
use std::cmp::Ordering;
89
use sys::{ffi_methods, GodotFfi};
910

10-
use crate::builtin::math::{GlamConv, GlamType, IVec2};
11-
use crate::builtin::Vector2;
11+
use crate::builtin::math::{FloatExt, GlamConv, GlamType};
12+
use crate::builtin::{real, RVec2, Vector2, Vector2Axis};
1213

1314
use std::fmt;
1415

@@ -56,6 +57,29 @@ impl Vector2i {
5657
Self { x, y }
5758
}
5859

60+
/// Aspect ratio: x / y, as a `real` value.
61+
pub fn aspect(self) -> real {
62+
self.x as real / self.y as real
63+
}
64+
65+
/// Axis of the vector's highest value. [`None`] if components are equal.
66+
pub fn max_axis(self) -> Option<Vector2Axis> {
67+
match self.x.cmp(&self.y) {
68+
Ordering::Less => Some(Vector2Axis::Y),
69+
Ordering::Equal => None,
70+
Ordering::Greater => Some(Vector2Axis::X),
71+
}
72+
}
73+
74+
/// Axis of the vector's highest value. [`None`] if components are equal.
75+
pub fn min_axis(self) -> Option<Vector2Axis> {
76+
match self.x.cmp(&self.y) {
77+
Ordering::Less => Some(Vector2Axis::X),
78+
Ordering::Equal => None,
79+
Ordering::Greater => Some(Vector2Axis::Y),
80+
}
81+
}
82+
5983
/// Constructs a new `Vector2i` with both components set to `v`.
6084
pub const fn splat(v: i32) -> Self {
6185
Self::new(v, v)
@@ -70,13 +94,18 @@ impl Vector2i {
7094
}
7195

7296
/// Converts the corresponding `glam` type to `Self`.
73-
fn from_glam(v: IVec2) -> Self {
97+
fn from_glam(v: glam::IVec2) -> Self {
7498
Self::new(v.x, v.y)
7599
}
76100

77101
/// Converts `self` to the corresponding `glam` type.
78102
fn to_glam(self) -> glam::IVec2 {
79-
IVec2::new(self.x, self.y)
103+
glam::IVec2::new(self.x, self.y)
104+
}
105+
106+
/// Converts `self` to the corresponding [`real`] `glam` type.
107+
fn to_glam_real(self) -> RVec2 {
108+
RVec2::new(self.x as real, self.y as real)
80109
}
81110

82111
pub fn coords(&self) -> (i32, i32) {
@@ -92,6 +121,8 @@ impl fmt::Display for Vector2i {
92121
}
93122

94123
impl_common_vector_fns!(Vector2i, i32);
124+
impl_integer_vector_glam_fns!(Vector2i, real);
125+
impl_integer_vector_component_fns!(Vector2i, real, (x, y));
95126
impl_vector_operators!(Vector2i, i32, (x, y));
96127
impl_from_tuple_for_vector2x!(Vector2i, i32);
97128

@@ -101,20 +132,20 @@ unsafe impl GodotFfi for Vector2i {
101132
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
102133
}
103134

104-
impl GlamType for IVec2 {
135+
impl GlamType for glam::IVec2 {
105136
type Mapped = Vector2i;
106137

107138
fn to_front(&self) -> Self::Mapped {
108139
Vector2i::new(self.x, self.y)
109140
}
110141

111142
fn from_front(mapped: &Self::Mapped) -> Self {
112-
IVec2::new(mapped.x, mapped.y)
143+
glam::IVec2::new(mapped.x, mapped.y)
113144
}
114145
}
115146

116147
impl GlamConv for Vector2i {
117-
type Glam = IVec2;
148+
type Glam = glam::IVec2;
118149
}
119150

120151
#[cfg(test)]
@@ -137,4 +168,16 @@ mod test {
137168

138169
crate::builtin::test_utils::roundtrip(&vector, expected_json);
139170
}
171+
172+
#[test]
173+
fn axis_min_max() {
174+
assert_eq!(Vector2i::new(10, 5).max_axis(), Some(Vector2Axis::X));
175+
assert_eq!(Vector2i::new(5, 10).max_axis(), Some(Vector2Axis::Y));
176+
177+
assert_eq!(Vector2i::new(-5, 5).min_axis(), Some(Vector2Axis::X));
178+
assert_eq!(Vector2i::new(5, -5).min_axis(), Some(Vector2Axis::Y));
179+
180+
assert_eq!(Vector2i::new(15, 15).max_axis(), None);
181+
assert_eq!(Vector2i::new(15, 15).min_axis(), None);
182+
}
140183
}

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

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7+
use std::cmp::Ordering;
78
use std::fmt;
89

910
use godot_ffi as sys;
1011
use sys::{ffi_methods, GodotFfi};
1112

12-
use crate::builtin::math::{GlamConv, GlamType, IVec3};
13-
use crate::builtin::Vector3;
13+
use crate::builtin::math::{FloatExt, GlamConv, GlamType};
14+
use crate::builtin::{real, RVec3, Vector3, Vector3Axis};
1415

1516
/// Vector used for 3D math using integer coordinates.
1617
///
@@ -65,6 +66,50 @@ impl Vector3i {
6566
Self { x, y, z }
6667
}
6768

69+
/// Axis of the vector's highest value. [`None`] if at least two components are equal.
70+
pub fn max_axis(self) -> Option<Vector3Axis> {
71+
use Vector3Axis::*;
72+
73+
match self.x.cmp(&self.y) {
74+
Ordering::Less => match self.y.cmp(&self.z) {
75+
Ordering::Less => Some(Z),
76+
Ordering::Equal => None,
77+
Ordering::Greater => Some(Y),
78+
},
79+
Ordering::Equal => match self.x.cmp(&self.z) {
80+
Ordering::Less => Some(Z),
81+
_ => None,
82+
},
83+
Ordering::Greater => match self.x.cmp(&self.z) {
84+
Ordering::Less => Some(Z),
85+
Ordering::Equal => None,
86+
Ordering::Greater => Some(X),
87+
},
88+
}
89+
}
90+
91+
/// Axis of the vector's highest value. [`None`] if at least two components are equal.
92+
pub fn min_axis(self) -> Option<Vector3Axis> {
93+
use Vector3Axis::*;
94+
95+
match self.x.cmp(&self.y) {
96+
Ordering::Less => match self.x.cmp(&self.z) {
97+
Ordering::Less => Some(X),
98+
Ordering::Equal => None,
99+
Ordering::Greater => Some(Z),
100+
},
101+
Ordering::Equal => match self.x.cmp(&self.z) {
102+
Ordering::Greater => Some(Z),
103+
_ => None,
104+
},
105+
Ordering::Greater => match self.y.cmp(&self.z) {
106+
Ordering::Less => Some(Y),
107+
Ordering::Equal => None,
108+
Ordering::Greater => Some(Z),
109+
},
110+
}
111+
}
112+
68113
/// Constructs a new `Vector3i` with all components set to `v`.
69114
pub const fn splat(v: i32) -> Self {
70115
Self::new(v, v, v)
@@ -80,13 +125,18 @@ impl Vector3i {
80125
}
81126

82127
/// Converts the corresponding `glam` type to `Self`.
83-
fn from_glam(v: IVec3) -> Self {
128+
fn from_glam(v: glam::IVec3) -> Self {
84129
Self::new(v.x, v.y, v.z)
85130
}
86131

87132
/// Converts `self` to the corresponding `glam` type.
88-
fn to_glam(self) -> IVec3 {
89-
IVec3::new(self.x, self.y, self.z)
133+
fn to_glam(self) -> glam::IVec3 {
134+
glam::IVec3::new(self.x, self.y, self.z)
135+
}
136+
137+
/// Converts `self` to the corresponding [`real`] `glam` type.
138+
fn to_glam_real(self) -> RVec3 {
139+
RVec3::new(self.x as real, self.y as real, self.z as real)
90140
}
91141

92142
pub fn coords(&self) -> (i32, i32, i32) {
@@ -102,6 +152,8 @@ impl fmt::Display for Vector3i {
102152
}
103153

104154
impl_common_vector_fns!(Vector3i, i32);
155+
impl_integer_vector_glam_fns!(Vector3i, real);
156+
impl_integer_vector_component_fns!(Vector3i, real, (x, y, z));
105157
impl_vector_operators!(Vector3i, i32, (x, y, z));
106158
impl_from_tuple_for_vector3x!(Vector3i, i32);
107159

@@ -111,20 +163,20 @@ unsafe impl GodotFfi for Vector3i {
111163
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
112164
}
113165

114-
impl GlamType for IVec3 {
166+
impl GlamType for glam::IVec3 {
115167
type Mapped = Vector3i;
116168

117169
fn to_front(&self) -> Self::Mapped {
118170
Vector3i::new(self.x, self.y, self.z)
119171
}
120172

121173
fn from_front(mapped: &Self::Mapped) -> Self {
122-
IVec3::new(mapped.x, mapped.y, mapped.z)
174+
glam::IVec3::new(mapped.x, mapped.y, mapped.z)
123175
}
124176
}
125177

126178
impl GlamConv for Vector3i {
127-
type Glam = IVec3;
179+
type Glam = glam::IVec3;
128180
}
129181

130182
#[cfg(test)]
@@ -147,4 +199,24 @@ mod test {
147199

148200
crate::builtin::test_utils::roundtrip(&vector, expected_json);
149201
}
202+
203+
#[test]
204+
fn axis_min_max() {
205+
assert_eq!(Vector3i::new(10, 5, -5).max_axis(), Some(Vector3Axis::X));
206+
assert_eq!(Vector3i::new(5, 10, -5).max_axis(), Some(Vector3Axis::Y));
207+
assert_eq!(Vector3i::new(5, -5, 10).max_axis(), Some(Vector3Axis::Z));
208+
209+
assert_eq!(Vector3i::new(-5, 5, 10).min_axis(), Some(Vector3Axis::X));
210+
assert_eq!(Vector3i::new(5, -5, 10).min_axis(), Some(Vector3Axis::Y));
211+
assert_eq!(Vector3i::new(5, 10, -5).min_axis(), Some(Vector3Axis::Z));
212+
213+
assert_eq!(Vector3i::new(15, 15, 5).max_axis(), None);
214+
assert_eq!(Vector3i::new(15, 15, 15).max_axis(), None);
215+
assert_eq!(Vector3i::new(15, 15, 25).min_axis(), None);
216+
assert_eq!(Vector3i::new(15, 15, 15).min_axis(), None);
217+
218+
// Checks for non-max / non-min equality "traps"
219+
assert_eq!(Vector3i::new(15, 15, 25).max_axis(), Some(Vector3Axis::Z));
220+
assert_eq!(Vector3i::new(15, 5, 15).min_axis(), Some(Vector3Axis::Y));
221+
}
150222
}

0 commit comments

Comments
 (0)