Skip to content

Commit e66ac03

Browse files
bors[bot]ttencateBromeon
authored
Merge #71
71: Implement the basics of built-in vector types r=Bromeon a=ttencate For Vector{2,3,4}{,i} this implements: - public fields - constructors - constants - operators - indexing by axis - (private) conversions to/from glam types - Display - a couple of functions like `abs()` and `length()` for demonstration See also #6. This PR supersedes #66. Co-authored-by: Thomas ten Cate <[email protected]> Co-authored-by: Jan Haller <[email protected]>
2 parents 9c5bdfd + e7fa8a8 commit e66ac03

File tree

9 files changed

+879
-123
lines changed

9 files changed

+879
-123
lines changed

examples/dodge-the-creeps/rust/src/player.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl GodotExt for Player {
6262
.base
6363
.get_node_as::<AnimatedSprite2D>("AnimatedSprite2D");
6464

65-
let mut velocity = Vector2::new(0.0, 0.0).inner();
65+
let mut velocity = Vector2::new(0.0, 0.0);
6666

6767
// Note: exact=false by default, in Rust we have to provide it explicitly
6868
let input = Input::singleton();
@@ -80,7 +80,7 @@ impl GodotExt for Player {
8080
}
8181

8282
if velocity.length() > 0.0 {
83-
velocity = velocity.normalize() * self.speed;
83+
velocity = velocity.normalized() * self.speed;
8484

8585
let animation;
8686

@@ -101,10 +101,10 @@ impl GodotExt for Player {
101101
}
102102

103103
let change = velocity * delta as f32;
104-
let position = self.base.get_global_position().inner() + change;
104+
let position = self.base.get_global_position() + change;
105105
let position = Vector2::new(
106-
position.x.max(0.0).min(self.screen_size.inner().x),
107-
position.y.max(0.0).min(self.screen_size.inner().y),
106+
position.x.max(0.0).min(self.screen_size.x),
107+
position.y.max(0.0).min(self.screen_size.y),
108108
);
109109
self.base.set_global_position(position);
110110
}

godot-core/src/builtin/mod.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,36 @@
44
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
55
*/
66

7-
//! Built-in types like `Vector2`, `GodotString` or `Variant`.
7+
//! Built-in types like `Vector2`, `GodotString` and `Variant`.
8+
//!
9+
//! # Background on the design of vector algebra types
10+
//!
11+
//! The basic vector algebra types like `Vector2`, `Matrix4` and `Quaternion` are re-implemented
12+
//! here, with an API similar to that in the Godot engine itself. There are other approaches, but
13+
//! they all have their disadvantages:
14+
//!
15+
//! - We could invoke API methods from the engine. The implementations could be generated, but it
16+
//! is slower and prevents inlining.
17+
//!
18+
//! - We could re-export types from an existing vector algebra crate, like `glam`. This removes the
19+
//! duplication, but it would create a strong dependency on a volatile API outside our control.
20+
//! The `gdnative` crate started out this way, using types from `euclid`, but [found it
21+
//! impractical](https://github.com/godot-rust/gdnative/issues/594#issue-705061720). Moreover,
22+
//! the API would not match Godot's own, which would make porting from GDScript (slightly)
23+
//! harder.
24+
//!
25+
//! - We could opaquely wrap types from an existing vector algebra crate. This protects users of
26+
//! `gdextension` from changes in the wrapped crate. However, direct field access using `.x`,
27+
//! `.y`, `.z` is no longer possible. Instead of `v.y += a;` you would have to write
28+
//! `v.set_y(v.get_y() + a);`. (A `union` could be used to add these fields in the public API,
29+
//! but would make every field access unsafe, which is also not great.)
30+
//!
31+
//! - We could re-export types from the [`mint`](https://crates.io/crates/mint) crate, which was
32+
//! explicitly designed to solve this problem. However, it falls short because [operator
33+
//! overloading would become impossible](https://github.com/kvark/mint/issues/75).
834
935
mod macros;
36+
mod vector_macros;
1037

1138
mod arrays;
1239
mod color;
@@ -16,8 +43,11 @@ mod string;
1643
mod string_name;
1744
mod variant;
1845
mod vector2;
46+
mod vector2i;
1947
mod vector3;
48+
mod vector3i;
2049
mod vector4;
50+
mod vector4i;
2151

2252
pub mod meta;
2353

@@ -29,5 +59,8 @@ pub use string::*;
2959
pub use string_name::*;
3060
pub use variant::*;
3161
pub use vector2::*;
62+
pub use vector2i::*;
3263
pub use vector3::*;
64+
pub use vector3i::*;
3365
pub use vector4::*;
66+
pub use vector4i::*;

godot-core/src/builtin/vector2.rs

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

7+
use std::fmt;
8+
79
use godot_ffi as sys;
810
use sys::{ffi_methods, GodotFfi};
911

10-
type Inner = glam::f32::Vec2;
11-
//type Inner = glam::f64::DVec2;
12+
use crate::builtin::Vector2i;
1213

13-
#[derive(Default, Copy, Clone, Debug, PartialEq)]
14+
/// Vector used for 2D math using floating point coordinates.
15+
///
16+
/// 2-element structure that can be used to represent positions in 2D space or any other pair of
17+
/// numeric values.
18+
///
19+
/// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which
20+
/// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit
21+
/// vectors, but this is not yet supported in the `gdextension` crate.
22+
///
23+
/// See [`Vector2i`] for its integer counterpart.
24+
#[derive(Debug, Default, Clone, Copy, PartialEq)]
1425
#[repr(C)]
1526
pub struct Vector2 {
16-
inner: Inner,
27+
/// The vector's X component.
28+
pub x: f32,
29+
/// The vector's Y component.
30+
pub y: f32,
1731
}
1832

1933
impl Vector2 {
20-
pub fn new(x: f32, y: f32) -> Self {
21-
Self {
22-
inner: Inner::new(x, y),
23-
}
34+
/// Vector with all components set to `0.0`.
35+
pub const ZERO: Self = Self::splat(0.0);
36+
37+
/// Vector with all components set to `1.0`.
38+
pub const ONE: Self = Self::splat(1.0);
39+
40+
/// Vector with all components set to `f32::INFINITY`.
41+
pub const INF: Self = Self::splat(f32::INFINITY);
42+
43+
/// Unit vector in -X direction (right in 2D coordinate system).
44+
pub const LEFT: Self = Self::new(-1.0, 0.0);
45+
46+
/// Unit vector in +X direction (right in 2D coordinate system).
47+
pub const RIGHT: Self = Self::new(1.0, 0.0);
48+
49+
/// Unit vector in -Y direction (up in 2D coordinate system).
50+
pub const UP: Self = Self::new(0.0, -1.0);
51+
52+
/// Unit vector in +Y direction (down in 2D coordinate system).
53+
pub const DOWN: Self = Self::new(0.0, 1.0);
54+
55+
/// Constructs a new `Vector2` from the given `x` and `y`.
56+
pub const fn new(x: f32, y: f32) -> Self {
57+
Self { x, y }
2458
}
2559

26-
pub fn from_inner(inner: Inner) -> Self {
27-
Self { inner }
60+
/// Constructs a new `Vector2` with both components set to `v`.
61+
pub const fn splat(v: f32) -> Self {
62+
Self::new(v, v)
2863
}
2964

30-
/// only for testing
31-
pub fn inner(self) -> Inner {
32-
self.inner
65+
/// Constructs a new `Vector2` from a [`Vector2i`].
66+
pub const fn from_vector2i(v: Vector2i) -> Self {
67+
Self {
68+
x: v.x as f32,
69+
y: v.y as f32,
70+
}
3371
}
3472

35-
// Hacks for example
36-
// pub fn length(self) -> f32 {
37-
// self.inner.length()
38-
// }
39-
// pub fn normalized(self) -> Vector2 {
40-
// Self::from_inner(self.inner.normalize())
41-
// }
73+
/// Returns the result of rotating this vector by `angle` (in radians).
4274
pub fn rotated(self, angle: f32) -> Self {
43-
Self::from_inner(glam::Affine2::from_angle(angle).transform_vector2(self.inner))
75+
Self::from_glam(glam::Affine2::from_angle(angle).transform_vector2(self.to_glam()))
4476
}
45-
}
4677

47-
impl GodotFfi for Vector2 {
48-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
49-
}
78+
/// Converts the corresponding `glam` type to `Self`.
79+
fn from_glam(v: glam::Vec2) -> Self {
80+
Self::new(v.x, v.y)
81+
}
5082

51-
impl std::fmt::Display for Vector2 {
52-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53-
self.inner.fmt(f)
83+
/// Converts `self` to the corresponding `glam` type.
84+
fn to_glam(self) -> glam::Vec2 {
85+
glam::Vec2::new(self.x, self.y)
5486
}
5587
}
5688

57-
// ----------------------------------------------------------------------------------------------------------------------------------------------
89+
/// Formats the vector like Godot: `(x, y)`.
90+
impl fmt::Display for Vector2 {
91+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92+
write!(f, "({}, {})", self.x, self.y)
93+
}
94+
}
5895

59-
type IInner = glam::IVec2;
96+
impl_common_vector_fns!(Vector2, f32);
97+
impl_float_vector_fns!(Vector2, f32);
98+
impl_vector_operators!(Vector2, f32, (x, y));
99+
impl_vector_index!(Vector2, f32, (x, y), Vector2Axis, (X, Y));
60100

61-
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
62-
#[repr(C)]
63-
pub struct Vector2i {
64-
inner: IInner,
101+
impl GodotFfi for Vector2 {
102+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
65103
}
66104

67-
impl Vector2i {
68-
pub fn new(x: i32, y: i32) -> Self {
69-
Self {
70-
inner: IInner::new(x, y),
71-
}
72-
}
105+
/// Enumerates the axes in a [`Vector2`].
106+
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
107+
#[repr(i32)]
108+
pub enum Vector2Axis {
109+
/// The X axis.
110+
X,
111+
/// The Y axis.
112+
Y,
73113
}
74114

75-
impl GodotFfi for Vector2i {
115+
impl GodotFfi for Vector2Axis {
76116
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
77117
}
78-
79-
impl std::fmt::Display for Vector2i {
80-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81-
self.inner.fmt(f)
82-
}
83-
}

godot-core/src/builtin/vector2i.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
use std::fmt;
8+
9+
use godot_ffi as sys;
10+
use sys::{ffi_methods, GodotFfi};
11+
12+
use crate::builtin::Vector2;
13+
14+
/// Vector used for 2D math using integer coordinates.
15+
///
16+
/// 2-element structure that can be used to represent positions in 2D space or any other pair of
17+
/// numeric values.
18+
///
19+
/// It uses integer coordinates and is therefore preferable to [`Vector2`] when exact precision is
20+
/// required. Note that the values are limited to 32 bits, and unlike [`Vector2`] this cannot be
21+
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
22+
/// needed.
23+
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
24+
#[repr(C)]
25+
pub struct Vector2i {
26+
/// The vector's X component.
27+
pub x: i32,
28+
/// The vector's Y component.
29+
pub y: i32,
30+
}
31+
32+
impl Vector2i {
33+
/// Vector with all components set to `0`.
34+
pub const ZERO: Self = Self::splat(0);
35+
36+
/// Vector with all components set to `1`.
37+
pub const ONE: Self = Self::splat(1);
38+
39+
/// Unit vector in -X direction (right in 2D coordinate system).
40+
pub const LEFT: Self = Self::new(-1, 0);
41+
42+
/// Unit vector in +X direction (right in 2D coordinate system).
43+
pub const RIGHT: Self = Self::new(1, 0);
44+
45+
/// Unit vector in -Y direction (up in 2D coordinate system).
46+
pub const UP: Self = Self::new(0, -1);
47+
48+
/// Unit vector in +Y direction (down in 2D coordinate system).
49+
pub const DOWN: Self = Self::new(0, 1);
50+
51+
/// Constructs a new `Vector2i` from the given `x` and `y`.
52+
pub const fn new(x: i32, y: i32) -> Self {
53+
Self { x, y }
54+
}
55+
56+
/// Constructs a new `Vector2i` with both components set to `v`.
57+
pub const fn splat(v: i32) -> Self {
58+
Self::new(v, v)
59+
}
60+
61+
/// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be truncated.
62+
pub const fn from_vector2(v: Vector2) -> Self {
63+
Self {
64+
x: v.x as i32,
65+
y: v.y as i32,
66+
}
67+
}
68+
69+
/// Converts the corresponding `glam` type to `Self`.
70+
fn from_glam(v: glam::IVec2) -> Self {
71+
Self::new(v.x, v.y)
72+
}
73+
74+
/// Converts `self` to the corresponding `glam` type.
75+
fn to_glam(self) -> glam::IVec2 {
76+
glam::IVec2::new(self.x, self.y)
77+
}
78+
}
79+
80+
/// Formats the vector like Godot: `(x, y)`.
81+
impl fmt::Display for Vector2i {
82+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83+
write!(f, "({}, {})", self.x, self.y)
84+
}
85+
}
86+
87+
impl_common_vector_fns!(Vector2i, i32);
88+
impl_vector_operators!(Vector2i, i32, (x, y));
89+
impl_vector_index!(Vector2i, i32, (x, y), Vector2iAxis, (X, Y));
90+
91+
impl GodotFfi for Vector2i {
92+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
93+
}
94+
95+
/// Enumerates the axes in a [`Vector2i`].
96+
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
97+
#[repr(i32)]
98+
pub enum Vector2iAxis {
99+
/// The X axis.
100+
X,
101+
/// The Y axis.
102+
Y,
103+
}
104+
105+
impl GodotFfi for Vector2iAxis {
106+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
107+
}

0 commit comments

Comments
 (0)