From 66a487afd1493186521191cc4b8fc77e3e465d28 Mon Sep 17 00:00:00 2001 From: Thomas ten Cate Date: Tue, 17 Jan 2023 12:29:30 +0100 Subject: [PATCH 1/2] Implement the basics of built-in vector types 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. --- examples/dodge-the-creeps/rust/src/player.rs | 10 +- godot-core/src/builtin/mod.rs | 35 ++- godot-core/src/builtin/vector2.rs | 127 +++++---- godot-core/src/builtin/vector2i.rs | 105 +++++++ godot-core/src/builtin/vector3.rs | 119 +++++--- godot-core/src/builtin/vector3i.rs | 115 ++++++++ godot-core/src/builtin/vector4.rs | 105 ++++--- godot-core/src/builtin/vector4i.rs | 100 +++++++ godot-core/src/builtin/vector_macros.rs | 275 +++++++++++++++++++ 9 files changed, 866 insertions(+), 125 deletions(-) create mode 100644 godot-core/src/builtin/vector2i.rs create mode 100644 godot-core/src/builtin/vector3i.rs create mode 100644 godot-core/src/builtin/vector4i.rs create mode 100644 godot-core/src/builtin/vector_macros.rs diff --git a/examples/dodge-the-creeps/rust/src/player.rs b/examples/dodge-the-creeps/rust/src/player.rs index 0d8a1c563..f24265129 100644 --- a/examples/dodge-the-creeps/rust/src/player.rs +++ b/examples/dodge-the-creeps/rust/src/player.rs @@ -62,7 +62,7 @@ impl GodotExt for Player { .base .get_node_as::("AnimatedSprite2D"); - let mut velocity = Vector2::new(0.0, 0.0).inner(); + let mut velocity = Vector2::new(0.0, 0.0); // Note: exact=false by default, in Rust we have to provide it explicitly let input = Input::singleton(); @@ -80,7 +80,7 @@ impl GodotExt for Player { } if velocity.length() > 0.0 { - velocity = velocity.normalize() * self.speed; + velocity = velocity.normalized() * self.speed; let animation; @@ -101,10 +101,10 @@ impl GodotExt for Player { } let change = velocity * delta as f32; - let position = self.base.get_global_position().inner() + change; + let position = self.base.get_global_position() + change; let position = Vector2::new( - position.x.max(0.0).min(self.screen_size.inner().x), - position.y.max(0.0).min(self.screen_size.inner().y), + position.x.max(0.0).min(self.screen_size.x), + position.y.max(0.0).min(self.screen_size.y), ); self.base.set_global_position(position); } diff --git a/godot-core/src/builtin/mod.rs b/godot-core/src/builtin/mod.rs index 9f8c83c4a..56e3b8855 100644 --- a/godot-core/src/builtin/mod.rs +++ b/godot-core/src/builtin/mod.rs @@ -4,9 +4,36 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -//! Built-in types like `Vector2`, `GodotString` or `Variant`. +//! Built-in types like `Vector2`, `GodotString` and `Variant`. +//! +//! # Background on the design of vector algebra types +//! +//! The basic vector algebra types like `Vector2`, `Matrix4` and `Quaternion` are re-implemented +//! here, with an API similar to that in the Godot engine itself. There are other approaches, but +//! they all have their disadvantages: +//! +//! - We could invoke API methods from the engine. The implementations could be generated, but it +//! is slower and prevents inlining. +//! +//! - We could re-export types from an existing vector algebra crate, like `glam`. This removes the +//! duplication, but it would create a strong dependency on a volatile API outside our control. +//! The `gdnative` crate started out this way, using types from `euclid`, but [found it +//! impractical](https://github.com/godot-rust/gdnative/issues/594#issue-705061720). Moreover, +//! the API would not match Godot's own, which would make porting from GDScript (slightly) +//! harder. +//! +//! - We could opaquely wrap types from an existing vector algebra crate. This protects users of +//! `gdextension` from changes in the wrapped crate. However, direct field access using `.x`, +//! `.y`, `.z` is no longer possible. Instead of `v.y += a;` you would have to write +//! `v.set_y(v.get_y() + a);`. (A `union` could be used to add these fields in the public API, +//! but would make every field access unsafe, which is also not great.) +//! +//! - We could re-export types from the [`mint`](https://crates.io/crates/mint) crate, which was +//! explicitly designed to solve this problem. However, it falls short because [operator +//! overloading would become impossible](https://github.com/kvark/mint/issues/75). mod macros; +mod vector_macros; mod arrays; mod color; @@ -16,8 +43,11 @@ mod string; mod string_name; mod variant; mod vector2; +mod vector2i; mod vector3; +mod vector3i; mod vector4; +mod vector4i; pub mod meta; @@ -29,5 +59,8 @@ pub use string::*; pub use string_name::*; pub use variant::*; pub use vector2::*; +pub use vector2i::*; pub use vector3::*; +pub use vector3i::*; pub use vector4::*; +pub use vector4i::*; diff --git a/godot-core/src/builtin/vector2.rs b/godot-core/src/builtin/vector2.rs index 2e3eb6dc9..c9e559387 100644 --- a/godot-core/src/builtin/vector2.rs +++ b/godot-core/src/builtin/vector2.rs @@ -4,80 +4,111 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::fmt; + use godot_ffi as sys; use sys::{ffi_methods, GodotFfi}; -type Inner = glam::f32::Vec2; -//type Inner = glam::f64::DVec2; +use crate::builtin::Vector2i; -#[derive(Default, Copy, Clone, Debug, PartialEq)] +/// Vector used for 2D math using floating point coordinates. +/// +/// 2-element structure that can be used to represent positions in 2D space or any other pair of +/// numeric values. +/// +/// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which +/// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit +/// vectors, but this is not yet supported in the `gdextension` crate. +/// +/// See [`Vector2i`] for its integer counterpart. +#[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] pub struct Vector2 { - inner: Inner, + /// The vector's X component. + pub x: f32, + /// The vector's Y component. + pub y: f32, } +impl_vector_operators!(Vector2, f32, (x, y)); +impl_vector_index!(Vector2, f32, (x, y), Vector2Axis, (X, Y)); +impl_common_vector_fns!(Vector2, f32); +impl_float_vector_fns!(Vector2, f32); + impl Vector2 { - pub fn new(x: f32, y: f32) -> Self { - Self { - inner: Inner::new(x, y), - } + /// Constructs a new `Vector2` from the given `x` and `y`. + pub const fn new(x: f32, y: f32) -> Self { + Self { x, y } } - pub fn from_inner(inner: Inner) -> Self { - Self { inner } + /// Constructs a new `Vector2` with all components set to `v`. + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v } } - /// only for testing - pub fn inner(self) -> Inner { - self.inner + /// Constructs a new `Vector2` from a [`Vector2i`]. + pub const fn from_vector2i(v: Vector2i) -> Self { + Self { x: v.x as f32, y: v.y as f32 } } - // Hacks for example - // pub fn length(self) -> f32 { - // self.inner.length() - // } - // pub fn normalized(self) -> Vector2 { - // Self::from_inner(self.inner.normalize()) - // } - pub fn rotated(self, angle: f32) -> Self { - Self::from_inner(glam::Affine2::from_angle(angle).transform_vector2(self.inner)) - } -} + /// Zero vector, a vector with all components set to `0.0`. + pub const ZERO: Self = Self::splat(0.0); -impl GodotFfi for Vector2 { - ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } -} + /// One vector, a vector with all components set to `1.0`. + pub const ONE: Self = Self::splat(1.0); -impl std::fmt::Display for Vector2 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) - } -} + /// Infinity vector, a vector with all components set to `INFIINTY`. + pub const INF: Self = Self::splat(f32::INFINITY); -// ---------------------------------------------------------------------------------------------------------------------------------------------- + /// Left unit vector. Represents the direction of left. + pub const LEFT: Self = Self::new(-1.0, 0.0); -type IInner = glam::IVec2; + /// Right unit vector. Represents the direction of right. + pub const RIGHT: Self = Self::new(1.0, 0.0); -#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)] -#[repr(C)] -pub struct Vector2i { - inner: IInner, + /// Up unit vector. Y is down in 2D, so this vector points -Y. + pub const UP: Self = Self::new(0.0, -1.0); + + /// Down unit vector. Y is down in 2D, so this vector points +Y. + pub const DOWN: Self = Self::new(0.0, 1.0); + + /// Returns the result of rotating this vector by `angle` (in radians). + pub fn rotated(self, angle: f32) -> Self { + Self::from_glam(glam::Affine2::from_angle(angle).transform_vector2(self.to_glam())) + } + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::Vec2) -> Self { + Self::new(v.x, v.y) + } + + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::Vec2 { + glam::Vec2::new(self.x, self.y) + } } -impl Vector2i { - pub fn new(x: i32, y: i32) -> Self { - Self { - inner: IInner::new(x, y), - } +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {})", self.x, self.y) } } -impl GodotFfi for Vector2i { +impl GodotFfi for Vector2 { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } -impl std::fmt::Display for Vector2i { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) - } +/// Enumerates the axes in a [`Vector2`]. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[repr(i32)] +pub enum Vector2Axis { + /// The X axis. + X, + /// The Y axis. + Y, +} + +impl GodotFfi for Vector2Axis { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector2i.rs b/godot-core/src/builtin/vector2i.rs new file mode 100644 index 000000000..ebce0bf4d --- /dev/null +++ b/godot-core/src/builtin/vector2i.rs @@ -0,0 +1,105 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use std::fmt; + +use godot_ffi as sys; +use sys::{ffi_methods, GodotFfi}; + +use crate::builtin::Vector2; + +/// Vector used for 2D math using integer coordinates. +/// +/// 2-element structure that can be used to represent positions in 2D space or any other pair of +/// numeric values. +/// +/// It uses integer coordinates and is therefore preferable to [`Vector2`] when exact precision is +/// required. Note that the values are limited to 32 bits, and unlike [`Vector2`] this cannot be +/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are +/// needed. +#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct Vector2i { + /// The vector's X component. + pub x: i32, + /// The vector's Y component. + pub y: i32, +} + +impl_vector_operators!(Vector2i, i32, (x, y)); +impl_vector_index!(Vector2i, i32, (x, y), Vector2iAxis, (X, Y)); +impl_common_vector_fns!(Vector2i, i32); + +impl Vector2i { + /// Constructs a new `Vector2i` from the given `x` and `y`. + pub const fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Constructs a new `Vector2i` with all components set to `v`. + pub const fn splat(v: i32) -> Self { + Self { x: v, y: v } + } + + /// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be + /// truncated. + pub const fn from_vector2(v: Vector2) -> Self { + Self { x: v.x as i32, y: v.y as i32 } + } + + /// Zero vector, a vector with all components set to `0`. + pub const ZERO: Self = Self::splat(0); + + /// One vector, a vector with all components set to `1`. + pub const ONE: Self = Self::splat(1); + + /// Left unit vector. Represents the direction of left. + pub const LEFT: Self = Self::new(-1, 0); + + /// Right unit vector. Represents the direction of right. + pub const RIGHT: Self = Self::new(1, 0); + + /// Up unit vector. Y is down in 2D, so this vector points -Y. + pub const UP: Self = Self::new(0, -1); + + /// Down unit vector. Y is down in 2D, so this vector points +Y. + pub const DOWN: Self = Self::new(0, 1); + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::IVec2) -> Self { + Self::new(v.x, v.y) + } + + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::IVec2 { + glam::IVec2::new(self.x, self.y) + } +} + +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector2i { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {})", self.x, self.y) + } +} + +impl GodotFfi for Vector2i { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} + +/// Enumerates the axes in a [`Vector2i`]. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[repr(i32)] +pub enum Vector2iAxis { + /// The X axis. + X, + /// The Y axis. + Y, +} + +impl GodotFfi for Vector2iAxis { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} diff --git a/godot-core/src/builtin/vector3.rs b/godot-core/src/builtin/vector3.rs index 0f2b94954..a01398281 100644 --- a/godot-core/src/builtin/vector3.rs +++ b/godot-core/src/builtin/vector3.rs @@ -4,75 +4,114 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::fmt; + use godot_ffi as sys; use sys::{ffi_methods, GodotFfi}; -type Inner = glam::f32::Vec3; -// type Inner = glam::f64::DVec3; - -#[derive(Default, Copy, Clone, Debug, PartialEq)] +use crate::builtin::Vector3i; + +/// Vector used for 3D math using floating point coordinates. +/// +/// 2-element structure that can be used to represent positions in 2D space or any other pair of +/// numeric values. +/// +/// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which +/// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit +/// vectors, but this is not yet supported in the `gdextension` crate. +/// +/// See [`Vector3i`] for its integer counterpart. +#[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] pub struct Vector3 { - inner: Inner, + /// The vector's X component. + pub x: f32, + /// The vector's Y component. + pub y: f32, + /// The vector's Z component. + pub z: f32, } +impl_vector_operators!(Vector3, f32, (x, y, z)); +impl_vector_index!(Vector3, f32, (x, y, z), Vector3Axis, (X, Y, Z)); +impl_common_vector_fns!(Vector3, f32); +impl_float_vector_fns!(Vector3, f32); + impl Vector3 { - pub fn new(x: f32, y: f32, z: f32) -> Self { - Self { - inner: Inner::new(x, y, z), - } + /// Returns a `Vector3` with the given components. + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self { x, y, z } } -} -impl GodotFfi for Vector3 { - ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } -} + /// Returns a new `Vector3` with all components set to `v`. + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v, z: v } + } -impl std::fmt::Display for Vector3 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - //let Inner {x, y, z} = self.inner; - //write!(f, "({x}, {y}, {z})") - self.inner.fmt(f) + /// Constructs a new `Vector3` from a [`Vector3i`]. + pub const fn from_vector3i(v: Vector3i) -> Self { + Self { x: v.x as f32, y: v.y as f32, z: v.z as f32 } } -} -// ---------------------------------------------------------------------------------------------------------------------------------------------- + /// Zero vector, a vector with all components set to `0.0`. + pub const ZERO: Self = Self::splat(0.0); -type IInner = glam::IVec3; + /// One vector, a vector with all components set to `1.0`. + pub const ONE: Self = Self::splat(1.0); -#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)] -#[repr(C)] -pub struct Vector3i { - inner: IInner, -} + /// Infinity vector, a vector with all components set to `INFIINTY`. + pub const INF: Self = Self::splat(f32::INFINITY); + + /// Left unit vector. Represents the local direction of left, and the global direction of west. + pub const LEFT: Self = Self::new(-1.0, 0.0, 0.0); -impl Vector3i { - pub fn new(x: i32, y: i32, z: i32) -> Self { - Self { - inner: IInner::new(x, y, z), - } + /// Right unit vector. Represents the local direction of right, and the global direction of east. + pub const RIGHT: Self = Self::new(1.0, 0.0, 0.0); + + /// Up unit vector. + pub const UP: Self = Self::new(0.0, -1.0, 0.0); + + /// Down unit vector. + pub const DOWN: Self = Self::new(0.0, 1.0, 0.0); + + /// Forward unit vector. Represents the local direction of forward, and the global direction of north. + pub const FORWARD: Self = Self::new(0.0, 0.0, -1.0); + + /// Back unit vector. Represents the local direction of back, and the global direction of south. + pub const BACK: Self = Self::new(0.0, 0.0, 1.0); + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::Vec3) -> Self { + Self::new(v.x, v.y, v.z) } -} -impl GodotFfi for Vector3i { - ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::Vec3 { + glam::Vec3::new(self.x, self.y, self.z) + } } -impl std::fmt::Display for Vector3i { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector3 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {})", self.x, self.y, self.z) } } -// ---------------------------------------------------------------------------------------------------------------------------------------------- +impl GodotFfi for Vector3 { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} +/// Enumerates the axes in a [`Vector3`]. // TODO auto-generate this, alongside all the other builtin type's enums - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] #[repr(i32)] pub enum Vector3Axis { + /// The X axis. X, + /// The Y axis. Y, + /// The Z axis. Z, } diff --git a/godot-core/src/builtin/vector3i.rs b/godot-core/src/builtin/vector3i.rs new file mode 100644 index 000000000..808b645bf --- /dev/null +++ b/godot-core/src/builtin/vector3i.rs @@ -0,0 +1,115 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use std::fmt; + +use godot_ffi as sys; +use sys::{ffi_methods, GodotFfi}; + +use crate::builtin::Vector3; + +/// Vector used for 3D math using integer coordinates. +/// +/// 3-element structure that can be used to represent positions in 3D space or any other pair of +/// numeric values. +/// +/// It uses integer coordinates and is therefore preferable to [`Vector3`] when exact precision is +/// required. Note that the values are limited to 32 bits, and unlike [`Vector3`] this cannot be +/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are +/// needed. +#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct Vector3i { + /// The vector's X component. + pub x: i32, + /// The vector's Y component. + pub y: i32, + /// The vector's Z component. + pub z: i32, +} + +impl_vector_operators!(Vector3i, i32, (x, y, z)); +impl_vector_index!(Vector3i, i32, (x, y, z), Vector3iAxis, (X, Y, Z)); +impl_common_vector_fns!(Vector3i, i32); + +impl Vector3i { + /// Returns a `Vector3i` with the given components. + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Constructs a new `Vector3i` with all components set to `v`. + pub const fn splat(v: i32) -> Self { + Self { x: v, y: v, z: v } + } + + /// Constructs a new `Vector3i` from a [`Vector3`]. The floating point coordinates will be + /// truncated. + pub const fn from_vector3(v: Vector3) -> Self { + Self { x: v.x as i32, y: v.y as i32, z: v.z as i32 } + } + + /// Zero vector, a vector with all components set to `0`. + pub const ZERO: Self = Self::splat(0); + + /// One vector, a vector with all components set to `1`. + pub const ONE: Self = Self::splat(1); + + /// Left unit vector. Represents the local direction of left, and the global direction of west. + pub const LEFT: Self = Self::new(-1, 0, 0); + + /// Right unit vector. Represents the local direction of right, and the global direction of east. + pub const RIGHT: Self = Self::new(1, 0, 0); + + /// Up unit vector. + pub const UP: Self = Self::new(0, -1, 0); + + /// Down unit vector. + pub const DOWN: Self = Self::new(0, 1, 0); + + /// Forward unit vector. Represents the local direction of forward, and the global direction of north. + pub const FORWARD: Self = Self::new(0, 0, -1); + + /// Back unit vector. Represents the local direction of back, and the global direction of south. + pub const BACK: Self = Self::new(0, 0, 1); + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::IVec3) -> Self { + Self::new(v.x, v.y, v.z) + } + + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::IVec3 { + glam::IVec3::new(self.x, self.y, self.z) + } +} + +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector3i { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {})", self.x, self.y, self.z) + } +} + +impl GodotFfi for Vector3i { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} + +/// Enumerates the axes in a [`Vector3i`]. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[repr(i32)] +pub enum Vector3iAxis { + /// The X axis. + X, + /// The Y axis. + Y, + /// The Z axis. + Z, +} + +impl GodotFfi for Vector3iAxis { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} diff --git a/godot-core/src/builtin/vector4.rs b/godot-core/src/builtin/vector4.rs index 22e856ff8..73c365ba7 100644 --- a/godot-core/src/builtin/vector4.rs +++ b/godot-core/src/builtin/vector4.rs @@ -4,58 +4,101 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::fmt; + use godot_ffi as sys; use sys::{ffi_methods, GodotFfi}; -type Inner = glam::f32::Vec4; -//type Inner = glam::f64::DVec4; +use crate::builtin::Vector4i; -#[derive(Default, Copy, Clone, Debug, PartialEq)] +/// Vector used for 4D math using floating point coordinates. +/// +/// 4-element structure that can be used to represent any quadruplet of numeric values. +/// +/// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which +/// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit +/// vectors, but this is not yet supported in the `gdextension` crate. +/// +/// See [`Vector4i`] for its integer counterpart. +#[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] pub struct Vector4 { - inner: Inner, + /// The vector's X component. + pub x: f32, + /// The vector's Y component. + pub y: f32, + /// The vector's Z component. + pub z: f32, + /// The vector's W component. + pub w: f32, } +impl_vector_operators!(Vector4, f32, (x, y, z, w)); +impl_vector_index!(Vector4, f32, (x, y, z, w), Vector4Axis, (X, Y, Z, W)); +impl_common_vector_fns!(Vector4, f32); +impl_float_vector_fns!(Vector4, f32); + impl Vector4 { - pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self { - Self { - inner: Inner::new(x, y, z, w), - } + /// Returns a `Vector4` with the given components. + pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + Self { x, y, z, w } } -} -impl GodotFfi for Vector4 { - ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } -} + /// Returns a new `Vector4` with all components set to `v`. + pub const fn splat(v: f32) -> Self { + Self { x: v, y: v, z: v, w: v } + } -impl std::fmt::Display for Vector4 { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) + /// Constructs a new `Vector3` from a [`Vector3i`]. + pub const fn from_vector4i(v: Vector4i) -> Self { + Self { x: v.x as f32, y: v.y as f32, z: v.z as f32, w: v.w as f32 } } -} -type IInner = glam::IVec4; + /// Zero vector, a vector with all components set to `0.0`. + pub const ZERO: Self = Self::splat(0.0); -#[derive(Default, Copy, Clone, Debug)] -#[repr(C)] -pub struct Vector4i { - inner: IInner, + /// One vector, a vector with all components set to `1.0`. + pub const ONE: Self = Self::splat(1.0); + + /// Infinity vector, a vector with all components set to `INFIINTY`. + pub const INF: Self = Self::splat(f32::INFINITY); + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::Vec4) -> Self { + Self::new(v.x, v.y, v.z, v.w) + } + + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::Vec4 { + glam::Vec4::new(self.x, self.y, self.z, self.w) + } } -impl Vector4i { - pub fn new(x: i32, y: i32, z: i32, w: i32) -> Self { - Self { - inner: IInner::new(x, y, z, w), - } +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w) } } -impl GodotFfi for Vector4i { +impl GodotFfi for Vector4 { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } -impl std::fmt::Display for Vector4i { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner.fmt(f) - } +/// Enumerates the axes in a [`Vector4`]. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[repr(i32)] +pub enum Vector4Axis { + /// The X axis. + X, + /// The Y axis. + Y, + /// The Z axis. + Z, + /// The W axis. + W, +} + +impl GodotFfi for Vector4Axis { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector4i.rs b/godot-core/src/builtin/vector4i.rs new file mode 100644 index 000000000..33937d848 --- /dev/null +++ b/godot-core/src/builtin/vector4i.rs @@ -0,0 +1,100 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use std::fmt; + +use godot_ffi as sys; +use sys::{ffi_methods, GodotFfi}; + +use crate::builtin::Vector4; + +/// Vector used for 4D math using integer coordinates. +/// +/// 4-element structure that can be used to represent 4D grid coordinates or sets of integers. +/// +/// It uses integer coordinates and is therefore preferable to [`Vector4`] when exact precision is +/// required. Note that the values are limited to 32 bits, and unlike [`Vector4`] this cannot be +/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are +/// needed. +#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct Vector4i { + /// The vector's X component. + pub x: i32, + /// The vector's Y component. + pub y: i32, + /// The vector's Z component. + pub z: i32, + /// The vector's W component. + pub w: i32, +} + +impl_vector_operators!(Vector4i, i32, (x, y, z, w)); +impl_vector_index!(Vector4i, i32, (x, y, z, w), Vector4iAxis, (X, Y, Z, W)); +impl_common_vector_fns!(Vector4i, i32); + +impl Vector4i { + /// Returns a `Vector4i` with the given components. + pub const fn new(x: i32, y: i32, z: i32, w: i32) -> Self { + Self { x, y, z, w } + } + + /// Constructs a new `Vector4i` with all components set to `v`. + pub const fn splat(v: i32) -> Self { + Self { x: v, y: v, z: v, w: v } + } + + /// Constructs a new `Vector4i` from a [`Vector4`]. The floating point coordinates will be + /// truncated. + pub const fn from_vector3(v: Vector4) -> Self { + Self { x: v.x as i32, y: v.y as i32, z: v.z as i32, w: v.w as i32 } + } + + /// Zero vector, a vector with all components set to `0`. + pub const ZERO: Self = Self::splat(0); + + /// One vector, a vector with all components set to `1`. + pub const ONE: Self = Self::splat(1); + + /// Converts the corresponding `glam` type to `Self`. + fn from_glam(v: glam::IVec4) -> Self { + Self::new(v.x, v.y, v.z, v.w) + } + + /// Converts `self` to the corresponding `glam` type. + fn to_glam(self) -> glam::IVec4 { + glam::IVec4::new(self.x, self.y, self.z, self.w) + } +} + +/// Formats this vector in the same way the Godot engine would. +impl fmt::Display for Vector4i { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w) + } +} + +impl GodotFfi for Vector4i { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} + +/// Enumerates the axes in a [`Vector4i`]. +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[repr(i32)] +pub enum Vector4iAxis { + /// The X axis. + X, + /// The Y axis. + Y, + /// The Z axis. + Z, + /// The W axis. + W, +} + +impl GodotFfi for Vector4iAxis { + ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } +} diff --git a/godot-core/src/builtin/vector_macros.rs b/godot-core/src/builtin/vector_macros.rs new file mode 100644 index 000000000..a1de527af --- /dev/null +++ b/godot-core/src/builtin/vector_macros.rs @@ -0,0 +1,275 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#![macro_use] + +/// Implements a single unary operator for a vector type. Only used for `Neg` at the moment. +macro_rules! impl_vector_unary_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `Neg`. + $Operator:ident, + // Name of the function on the operator trait, for example `neg`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator for $Vector { + type Output = Self; + fn $func(mut self) -> Self::Output { + $( + self.$components = self.$components.$func(); + )* + self + } + } + } +} + +/// Implements a component-wise single infix binary operator between two vectors. +macro_rules! impl_vector_vector_binary_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `Add`. + $Operator:ident, + // Name of the function on the operator trait, for example `add`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator for $Vector { + type Output = Self; + fn $func(mut self, rhs: $Vector) -> Self::Output { + $( + self.$components = self.$components.$func(rhs.$components); + )* + self + } + } + } +} + +/// Implements a component-wise single infix binary operator between a vector on the left and a +/// scalar on the right-hand side. +macro_rules! impl_vector_scalar_binary_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `Add`. + $Operator:ident, + // Name of the function on the operator trait, for example `add`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator<$Scalar> for $Vector { + type Output = Self; + fn $func(mut self, rhs: $Scalar) -> Self::Output { + $( + self.$components = self.$components.$func(rhs); + )* + self + } + } + } +} + +/// Implements a component-wise single infix binary operator between a scalar on the left and a +/// vector on the right-hand side. +macro_rules! impl_scalar_vector_binary_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `Add`. + $Operator:ident, + // Name of the function on the operator trait, for example `add`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator<$Vector> for $Scalar { + type Output = $Vector; + fn $func(self, mut rhs: $Vector) -> Self::Output { + $( + rhs.$components = rhs.$components.$func(self); + )* + rhs + } + } + } +} + +/// Implements a single arithmetic assignment operator for a vector type, with a vector on the +/// right-hand side. +macro_rules! impl_vector_vector_assign_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `AddAssign`. + $Operator:ident, + // Name of the function on the operator trait, for example `add_assign`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator for $Vector { + fn $func(&mut self, rhs: $Vector) { + $( + self.$components.$func(rhs.$components); + )* + } + } + } +} + +/// Implements a single arithmetic assignment operator for a vector type, with a scalar on the +/// right-hand side. +macro_rules! impl_vector_scalar_assign_operator { + ( + // Name of the vector type. + $Vector:ty, + // Type of each individual component, for example `i32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the operator trait, for example `AddAssign`. + $Operator:ident, + // Name of the function on the operator trait, for example `add_assign`. + $func:ident$(,)? + ) => { + impl std::ops::$Operator<$Scalar> for $Vector { + fn $func(&mut self, rhs: $Scalar) { + $( + self.$components.$func(rhs); + )* + } + } + } +} + +/// Implements all common arithmetic operators on a built-in vector type. +macro_rules! impl_vector_operators { + ( + // Name of the vector type to be implemented, for example `Vector2`. + $Vector:ty, + // Type of each individual component, for example `f32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*)$(,)? + ) => { + impl_vector_unary_operator!($Vector, $Scalar, ($($components),*), Neg, neg); + impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Add, add); + impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Sub, sub); + impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); + impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); + impl_scalar_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); + impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); + impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); + impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Rem, rem); + impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Rem, rem); + impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), AddAssign, add_assign); + impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), SubAssign, sub_assign); + impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); + impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); + impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); + impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); + impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), RemAssign, rem_assign); + impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), RemAssign, rem_assign); + } +} + +/// Implements `Index` and `IndexMut` for a vector type, using an enum to indicate the desired axis. +macro_rules! impl_vector_index { + ( + // Name of the vector type to be implemented, for example `Vector2`. + $Vector:ty, + // Type of each individual component, for example `f32`. + $Scalar:ty, + // Names of the components, with parentheses, for example `(x, y)`. + ($($components:ident),*), + // Name of the enum type for the axes, for example `Vector2Axis`. + $AxisEnum:ty, + // Names of the enum variants, with parenthes, for example `(X, Y)`. + ($($AxisVariants:ident),*)$(,)? + ) => { + impl std::ops::Index<$AxisEnum> for $Vector { + type Output = $Scalar; + fn index(&self, axis: $AxisEnum) -> &$Scalar { + match axis { + $(<$AxisEnum>::$AxisVariants => &self.$components),* + } + } + } + + impl std::ops::IndexMut<$AxisEnum> for $Vector { + fn index_mut(&mut self, axis: $AxisEnum) -> &mut $Scalar { + match axis { + $(<$AxisEnum>::$AxisVariants => &mut self.$components),* + } + } + } + } +} + +/// Implements functions on vector types which make sense for both floating-point and integer +/// vectors. +macro_rules! impl_common_vector_fns { + ( + // Name of the vector type. + $Vector:ty, + // Type of target component, for example `f32`. + $Scalar:ty + ) => { + impl $Vector { + /// Returns a new vector with all components in absolute values (i.e. positive or + /// zero). + #[inline] + pub fn abs(self) -> Self { + Self::from_glam(self.to_glam().abs()) + } + } + } +} + +/// Implements common constants and methods for floating-point type vectors. Works for any vector +/// type that has `to_glam` and `from_glam` functions. +macro_rules! impl_float_vector_fns { + ( + // Name of the vector type. + $Vector:ty, + // Type of target component, for example `f32`. + $Scalar:ty + ) => { + impl $Vector { + /// Returns the length (magnitude) of this vector. + #[inline] + pub fn length(self) -> $Scalar { + self.to_glam().length() + } + + /// Returns the vector scaled to unit length. Equivalent to `self / self.length()`. See + /// also `is_normalized()`. + /// + /// If the vector is zero, the result is also zero. + #[inline] + pub fn normalized(self) -> Self { + Self::from_glam(self.to_glam().normalize_or_zero()) + } + } + } +} From e7fa8a812a98d5313e3b319e86bbf5c2ec776c4f Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Fri, 20 Jan 2023 23:36:39 +0100 Subject: [PATCH 2/2] Apply rustfmt and minor review feedback --- godot-core/src/builtin/vector2.rs | 61 +++++++++++----------- godot-core/src/builtin/vector2i.rs | 58 +++++++++++---------- godot-core/src/builtin/vector3.rs | 69 +++++++++++++------------ godot-core/src/builtin/vector3i.rs | 65 ++++++++++++----------- godot-core/src/builtin/vector4.rs | 15 ++++-- godot-core/src/builtin/vector4i.rs | 13 +++-- godot-core/src/builtin/vector_macros.rs | 10 ++-- 7 files changed, 153 insertions(+), 138 deletions(-) diff --git a/godot-core/src/builtin/vector2.rs b/godot-core/src/builtin/vector2.rs index c9e559387..9506086be 100644 --- a/godot-core/src/builtin/vector2.rs +++ b/godot-core/src/builtin/vector2.rs @@ -19,7 +19,7 @@ use crate::builtin::Vector2i; /// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which /// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit /// vectors, but this is not yet supported in the `gdextension` crate. -/// +/// /// See [`Vector2i`] for its integer counterpart. #[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] @@ -30,48 +30,46 @@ pub struct Vector2 { pub y: f32, } -impl_vector_operators!(Vector2, f32, (x, y)); -impl_vector_index!(Vector2, f32, (x, y), Vector2Axis, (X, Y)); -impl_common_vector_fns!(Vector2, f32); -impl_float_vector_fns!(Vector2, f32); - impl Vector2 { - /// Constructs a new `Vector2` from the given `x` and `y`. - pub const fn new(x: f32, y: f32) -> Self { - Self { x, y } - } - - /// Constructs a new `Vector2` with all components set to `v`. - pub const fn splat(v: f32) -> Self { - Self { x: v, y: v } - } - - /// Constructs a new `Vector2` from a [`Vector2i`]. - pub const fn from_vector2i(v: Vector2i) -> Self { - Self { x: v.x as f32, y: v.y as f32 } - } - - /// Zero vector, a vector with all components set to `0.0`. + /// Vector with all components set to `0.0`. pub const ZERO: Self = Self::splat(0.0); - /// One vector, a vector with all components set to `1.0`. + /// Vector with all components set to `1.0`. pub const ONE: Self = Self::splat(1.0); - /// Infinity vector, a vector with all components set to `INFIINTY`. + /// Vector with all components set to `f32::INFINITY`. pub const INF: Self = Self::splat(f32::INFINITY); - /// Left unit vector. Represents the direction of left. + /// Unit vector in -X direction (right in 2D coordinate system). pub const LEFT: Self = Self::new(-1.0, 0.0); - /// Right unit vector. Represents the direction of right. + /// Unit vector in +X direction (right in 2D coordinate system). pub const RIGHT: Self = Self::new(1.0, 0.0); - /// Up unit vector. Y is down in 2D, so this vector points -Y. + /// Unit vector in -Y direction (up in 2D coordinate system). pub const UP: Self = Self::new(0.0, -1.0); - /// Down unit vector. Y is down in 2D, so this vector points +Y. + /// Unit vector in +Y direction (down in 2D coordinate system). pub const DOWN: Self = Self::new(0.0, 1.0); + /// Constructs a new `Vector2` from the given `x` and `y`. + pub const fn new(x: f32, y: f32) -> Self { + Self { x, y } + } + + /// Constructs a new `Vector2` with both components set to `v`. + pub const fn splat(v: f32) -> Self { + Self::new(v, v) + } + + /// Constructs a new `Vector2` from a [`Vector2i`]. + pub const fn from_vector2i(v: Vector2i) -> Self { + Self { + x: v.x as f32, + y: v.y as f32, + } + } + /// Returns the result of rotating this vector by `angle` (in radians). pub fn rotated(self, angle: f32) -> Self { Self::from_glam(glam::Affine2::from_angle(angle).transform_vector2(self.to_glam())) @@ -88,13 +86,18 @@ impl Vector2 { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y)`. impl fmt::Display for Vector2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } +impl_common_vector_fns!(Vector2, f32); +impl_float_vector_fns!(Vector2, f32); +impl_vector_operators!(Vector2, f32, (x, y)); +impl_vector_index!(Vector2, f32, (x, y), Vector2Axis, (X, Y)); + impl GodotFfi for Vector2 { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector2i.rs b/godot-core/src/builtin/vector2i.rs index ebce0bf4d..b20a2dd87 100644 --- a/godot-core/src/builtin/vector2i.rs +++ b/godot-core/src/builtin/vector2i.rs @@ -15,7 +15,7 @@ use crate::builtin::Vector2; /// /// 2-element structure that can be used to represent positions in 2D space or any other pair of /// numeric values. -/// +/// /// It uses integer coordinates and is therefore preferable to [`Vector2`] when exact precision is /// required. Note that the values are limited to 32 bits, and unlike [`Vector2`] this cannot be /// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are @@ -29,45 +29,43 @@ pub struct Vector2i { pub y: i32, } -impl_vector_operators!(Vector2i, i32, (x, y)); -impl_vector_index!(Vector2i, i32, (x, y), Vector2iAxis, (X, Y)); -impl_common_vector_fns!(Vector2i, i32); - impl Vector2i { - /// Constructs a new `Vector2i` from the given `x` and `y`. - pub const fn new(x: i32, y: i32) -> Self { - Self { x, y } - } - - /// Constructs a new `Vector2i` with all components set to `v`. - pub const fn splat(v: i32) -> Self { - Self { x: v, y: v } - } - - /// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be - /// truncated. - pub const fn from_vector2(v: Vector2) -> Self { - Self { x: v.x as i32, y: v.y as i32 } - } - - /// Zero vector, a vector with all components set to `0`. + /// Vector with all components set to `0`. pub const ZERO: Self = Self::splat(0); - /// One vector, a vector with all components set to `1`. + /// Vector with all components set to `1`. pub const ONE: Self = Self::splat(1); - /// Left unit vector. Represents the direction of left. + /// Unit vector in -X direction (right in 2D coordinate system). pub const LEFT: Self = Self::new(-1, 0); - /// Right unit vector. Represents the direction of right. + /// Unit vector in +X direction (right in 2D coordinate system). pub const RIGHT: Self = Self::new(1, 0); - /// Up unit vector. Y is down in 2D, so this vector points -Y. + /// Unit vector in -Y direction (up in 2D coordinate system). pub const UP: Self = Self::new(0, -1); - /// Down unit vector. Y is down in 2D, so this vector points +Y. + /// Unit vector in +Y direction (down in 2D coordinate system). pub const DOWN: Self = Self::new(0, 1); + /// Constructs a new `Vector2i` from the given `x` and `y`. + pub const fn new(x: i32, y: i32) -> Self { + Self { x, y } + } + + /// Constructs a new `Vector2i` with both components set to `v`. + pub const fn splat(v: i32) -> Self { + Self::new(v, v) + } + + /// Constructs a new `Vector2i` from a [`Vector2`]. The floating point coordinates will be truncated. + pub const fn from_vector2(v: Vector2) -> Self { + Self { + x: v.x as i32, + y: v.y as i32, + } + } + /// Converts the corresponding `glam` type to `Self`. fn from_glam(v: glam::IVec2) -> Self { Self::new(v.x, v.y) @@ -79,13 +77,17 @@ impl Vector2i { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y)`. impl fmt::Display for Vector2i { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } +impl_common_vector_fns!(Vector2i, i32); +impl_vector_operators!(Vector2i, i32, (x, y)); +impl_vector_index!(Vector2i, i32, (x, y), Vector2iAxis, (X, Y)); + impl GodotFfi for Vector2i { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector3.rs b/godot-core/src/builtin/vector3.rs index a01398281..29b84b48d 100644 --- a/godot-core/src/builtin/vector3.rs +++ b/godot-core/src/builtin/vector3.rs @@ -13,13 +13,13 @@ use crate::builtin::Vector3i; /// Vector used for 3D math using floating point coordinates. /// -/// 2-element structure that can be used to represent positions in 2D space or any other pair of +/// 3-element structure that can be used to represent positions in 2D space or any other triple of /// numeric values. /// /// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which /// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit /// vectors, but this is not yet supported in the `gdextension` crate. -/// +/// /// See [`Vector3i`] for its integer counterpart. #[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] @@ -32,54 +32,50 @@ pub struct Vector3 { pub z: f32, } -impl_vector_operators!(Vector3, f32, (x, y, z)); -impl_vector_index!(Vector3, f32, (x, y, z), Vector3Axis, (X, Y, Z)); -impl_common_vector_fns!(Vector3, f32); -impl_float_vector_fns!(Vector3, f32); - impl Vector3 { - /// Returns a `Vector3` with the given components. - pub const fn new(x: f32, y: f32, z: f32) -> Self { - Self { x, y, z } - } - - /// Returns a new `Vector3` with all components set to `v`. - pub const fn splat(v: f32) -> Self { - Self { x: v, y: v, z: v } - } - - /// Constructs a new `Vector3` from a [`Vector3i`]. - pub const fn from_vector3i(v: Vector3i) -> Self { - Self { x: v.x as f32, y: v.y as f32, z: v.z as f32 } - } - - /// Zero vector, a vector with all components set to `0.0`. + /// Vector with all components set to `0.0`. pub const ZERO: Self = Self::splat(0.0); - /// One vector, a vector with all components set to `1.0`. + /// Vector with all components set to `1.0`. pub const ONE: Self = Self::splat(1.0); - /// Infinity vector, a vector with all components set to `INFIINTY`. - pub const INF: Self = Self::splat(f32::INFINITY); - - /// Left unit vector. Represents the local direction of left, and the global direction of west. + /// Unit vector in -X direction. Can be interpreted as left in an untransformed 3D world. pub const LEFT: Self = Self::new(-1.0, 0.0, 0.0); - /// Right unit vector. Represents the local direction of right, and the global direction of east. + /// Unit vector in +X direction. Can be interpreted as right in an untransformed 3D world. pub const RIGHT: Self = Self::new(1.0, 0.0, 0.0); - /// Up unit vector. + /// Unit vector in -Y direction. Typically interpreted as down in a 3D world. pub const UP: Self = Self::new(0.0, -1.0, 0.0); - /// Down unit vector. + /// Unit vector in +Y direction. Typically interpreted as up in a 3D world. pub const DOWN: Self = Self::new(0.0, 1.0, 0.0); - /// Forward unit vector. Represents the local direction of forward, and the global direction of north. + /// Unit vector in -Z direction. Can be interpreted as "into the screen" in an untransformed 3D world. pub const FORWARD: Self = Self::new(0.0, 0.0, -1.0); - /// Back unit vector. Represents the local direction of back, and the global direction of south. + /// Unit vector in +Z direction. Can be interpreted as "out of the screen" in an untransformed 3D world. pub const BACK: Self = Self::new(0.0, 0.0, 1.0); + /// Returns a `Vector3` with the given components. + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self { x, y, z } + } + + /// Returns a new `Vector3` with all components set to `v`. + pub const fn splat(v: f32) -> Self { + Self::new(v, v, v) + } + + /// Constructs a new `Vector3` from a [`Vector3i`]. + pub const fn from_vector3i(v: Vector3i) -> Self { + Self { + x: v.x as f32, + y: v.y as f32, + z: v.z as f32, + } + } + /// Converts the corresponding `glam` type to `Self`. fn from_glam(v: glam::Vec3) -> Self { Self::new(v.x, v.y, v.z) @@ -91,13 +87,18 @@ impl Vector3 { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y, z)`. impl fmt::Display for Vector3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {}, {})", self.x, self.y, self.z) } } +impl_common_vector_fns!(Vector3, f32); +impl_float_vector_fns!(Vector3, f32); +impl_vector_operators!(Vector3, f32, (x, y, z)); +impl_vector_index!(Vector3, f32, (x, y, z), Vector3Axis, (X, Y, Z)); + impl GodotFfi for Vector3 { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector3i.rs b/godot-core/src/builtin/vector3i.rs index 808b645bf..f42036412 100644 --- a/godot-core/src/builtin/vector3i.rs +++ b/godot-core/src/builtin/vector3i.rs @@ -13,9 +13,9 @@ use crate::builtin::Vector3; /// Vector used for 3D math using integer coordinates. /// -/// 3-element structure that can be used to represent positions in 3D space or any other pair of +/// 3-element structure that can be used to represent positions in 3D space or any other triple of /// numeric values. -/// +/// /// It uses integer coordinates and is therefore preferable to [`Vector3`] when exact precision is /// required. Note that the values are limited to 32 bits, and unlike [`Vector3`] this cannot be /// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are @@ -31,51 +31,50 @@ pub struct Vector3i { pub z: i32, } -impl_vector_operators!(Vector3i, i32, (x, y, z)); -impl_vector_index!(Vector3i, i32, (x, y, z), Vector3iAxis, (X, Y, Z)); -impl_common_vector_fns!(Vector3i, i32); - impl Vector3i { - /// Returns a `Vector3i` with the given components. - pub const fn new(x: i32, y: i32, z: i32) -> Self { - Self { x, y, z } - } - - /// Constructs a new `Vector3i` with all components set to `v`. - pub const fn splat(v: i32) -> Self { - Self { x: v, y: v, z: v } - } - - /// Constructs a new `Vector3i` from a [`Vector3`]. The floating point coordinates will be - /// truncated. - pub const fn from_vector3(v: Vector3) -> Self { - Self { x: v.x as i32, y: v.y as i32, z: v.z as i32 } - } - - /// Zero vector, a vector with all components set to `0`. + /// Vector with all components set to `0`. pub const ZERO: Self = Self::splat(0); - /// One vector, a vector with all components set to `1`. + /// Vector with all components set to `1`. pub const ONE: Self = Self::splat(1); - /// Left unit vector. Represents the local direction of left, and the global direction of west. + /// Unit vector in -X direction. pub const LEFT: Self = Self::new(-1, 0, 0); - /// Right unit vector. Represents the local direction of right, and the global direction of east. + /// Unit vector in +X direction. pub const RIGHT: Self = Self::new(1, 0, 0); - /// Up unit vector. + /// Unit vector in -Y direction. pub const UP: Self = Self::new(0, -1, 0); - /// Down unit vector. + /// Unit vector in +Y direction. pub const DOWN: Self = Self::new(0, 1, 0); - /// Forward unit vector. Represents the local direction of forward, and the global direction of north. + /// Unit vector in -Z direction. pub const FORWARD: Self = Self::new(0, 0, -1); - /// Back unit vector. Represents the local direction of back, and the global direction of south. + /// Unit vector in +Z direction. pub const BACK: Self = Self::new(0, 0, 1); + /// Returns a `Vector3i` with the given components. + pub const fn new(x: i32, y: i32, z: i32) -> Self { + Self { x, y, z } + } + + /// Constructs a new `Vector3i` with all components set to `v`. + pub const fn splat(v: i32) -> Self { + Self::new(v, v, v) + } + + /// Constructs a new `Vector3i` from a [`Vector3`]. The floating point coordinates will be truncated. + pub const fn from_vector3(v: Vector3) -> Self { + Self { + x: v.x as i32, + y: v.y as i32, + z: v.z as i32, + } + } + /// Converts the corresponding `glam` type to `Self`. fn from_glam(v: glam::IVec3) -> Self { Self::new(v.x, v.y, v.z) @@ -87,13 +86,17 @@ impl Vector3i { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y, z)`. impl fmt::Display for Vector3i { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {}, {})", self.x, self.y, self.z) } } +impl_common_vector_fns!(Vector3i, i32); +impl_vector_operators!(Vector3i, i32, (x, y, z)); +impl_vector_index!(Vector3i, i32, (x, y, z), Vector3iAxis, (X, Y, Z)); + impl GodotFfi for Vector3i { ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. } } diff --git a/godot-core/src/builtin/vector4.rs b/godot-core/src/builtin/vector4.rs index 73c365ba7..9a8274010 100644 --- a/godot-core/src/builtin/vector4.rs +++ b/godot-core/src/builtin/vector4.rs @@ -18,7 +18,7 @@ use crate::builtin::Vector4i; /// It uses floating-point coordinates of 32-bit precision, unlike the engine's `float` type which /// is always 64-bit. The engine can be compiled with the option `precision=double` to use 64-bit /// vectors, but this is not yet supported in the `gdextension` crate. -/// +/// /// See [`Vector4i`] for its integer counterpart. #[derive(Debug, Default, Clone, Copy, PartialEq)] #[repr(C)] @@ -46,12 +46,17 @@ impl Vector4 { /// Returns a new `Vector4` with all components set to `v`. pub const fn splat(v: f32) -> Self { - Self { x: v, y: v, z: v, w: v } + Self::new(v, v, v, v) } /// Constructs a new `Vector3` from a [`Vector3i`]. pub const fn from_vector4i(v: Vector4i) -> Self { - Self { x: v.x as f32, y: v.y as f32, z: v.z as f32, w: v.w as f32 } + Self { + x: v.x as f32, + y: v.y as f32, + z: v.z as f32, + w: v.w as f32, + } } /// Zero vector, a vector with all components set to `0.0`. @@ -60,7 +65,7 @@ impl Vector4 { /// One vector, a vector with all components set to `1.0`. pub const ONE: Self = Self::splat(1.0); - /// Infinity vector, a vector with all components set to `INFIINTY`. + /// Infinity vector, a vector with all components set to `f32::INFINITY`. pub const INF: Self = Self::splat(f32::INFINITY); /// Converts the corresponding `glam` type to `Self`. @@ -74,7 +79,7 @@ impl Vector4 { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y, z, w)`. impl fmt::Display for Vector4 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w) diff --git a/godot-core/src/builtin/vector4i.rs b/godot-core/src/builtin/vector4i.rs index 33937d848..d8c341736 100644 --- a/godot-core/src/builtin/vector4i.rs +++ b/godot-core/src/builtin/vector4i.rs @@ -14,7 +14,7 @@ use crate::builtin::Vector4; /// Vector used for 4D math using integer coordinates. /// /// 4-element structure that can be used to represent 4D grid coordinates or sets of integers. -/// +/// /// It uses integer coordinates and is therefore preferable to [`Vector4`] when exact precision is /// required. Note that the values are limited to 32 bits, and unlike [`Vector4`] this cannot be /// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are @@ -44,13 +44,18 @@ impl Vector4i { /// Constructs a new `Vector4i` with all components set to `v`. pub const fn splat(v: i32) -> Self { - Self { x: v, y: v, z: v, w: v } + Self::new(v, v, v, v) } /// Constructs a new `Vector4i` from a [`Vector4`]. The floating point coordinates will be /// truncated. pub const fn from_vector3(v: Vector4) -> Self { - Self { x: v.x as i32, y: v.y as i32, z: v.z as i32, w: v.w as i32 } + Self { + x: v.x as i32, + y: v.y as i32, + z: v.z as i32, + w: v.w as i32, + } } /// Zero vector, a vector with all components set to `0`. @@ -70,7 +75,7 @@ impl Vector4i { } } -/// Formats this vector in the same way the Godot engine would. +/// Formats the vector like Godot: `(x, y, z, w)`. impl fmt::Display for Vector4i { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w) diff --git a/godot-core/src/builtin/vector_macros.rs b/godot-core/src/builtin/vector_macros.rs index a1de527af..addfde689 100644 --- a/godot-core/src/builtin/vector_macros.rs +++ b/godot-core/src/builtin/vector_macros.rs @@ -180,16 +180,12 @@ macro_rules! impl_vector_operators { impl_scalar_vector_binary_operator!($Vector, $Scalar, ($($components),*), Mul, mul); impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Div, div); - impl_vector_vector_binary_operator!($Vector, $Scalar, ($($components),*), Rem, rem); - impl_vector_scalar_binary_operator!($Vector, $Scalar, ($($components),*), Rem, rem); impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), AddAssign, add_assign); impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), SubAssign, sub_assign); impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), MulAssign, mul_assign); impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), DivAssign, div_assign); - impl_vector_vector_assign_operator!($Vector, $Scalar, ($($components),*), RemAssign, rem_assign); - impl_vector_scalar_assign_operator!($Vector, $Scalar, ($($components),*), RemAssign, rem_assign); } } @@ -205,7 +201,7 @@ macro_rules! impl_vector_index { // Name of the enum type for the axes, for example `Vector2Axis`. $AxisEnum:ty, // Names of the enum variants, with parenthes, for example `(X, Y)`. - ($($AxisVariants:ident),*)$(,)? + ($($AxisVariants:ident),*) ) => { impl std::ops::Index<$AxisEnum> for $Vector { type Output = $Scalar; @@ -243,7 +239,7 @@ macro_rules! impl_common_vector_fns { Self::from_glam(self.to_glam().abs()) } } - } + }; } /// Implements common constants and methods for floating-point type vectors. Works for any vector @@ -271,5 +267,5 @@ macro_rules! impl_float_vector_fns { Self::from_glam(self.to_glam().normalize_or_zero()) } } - } + }; }