Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions godot-core/src/builtin/glam_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ macro_rules! impl_glam_map_self {
}

impl_glam_map_self!(f32);
impl_glam_map_self!(bool);
impl_glam_map_self!((f32, f32, f32));
98 changes: 98 additions & 0 deletions godot-core/src/builtin/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use std::f32::consts::TAU;

pub const CMP_EPSILON: f32 = 0.00001;

pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
Expand Down Expand Up @@ -119,3 +121,99 @@ pub fn cubic_interpolate_in_time(
let b2 = lerp(a2, a3, if post_t == 0.0 { 1.0 } else { t / post_t });
lerp(b1, b2, if to_t == 0.0 { 0.5 } else { t / to_t })
}

/// Linearly interpolates between two angles (in radians) by a `weight` value
/// between 0.0 and 1.0.
///
/// Similar to [`lerp`], but interpolates correctly when the angles wrap around
/// [`TAU`].
///
/// The resulting angle is not normalized.
///
/// Note: This function lerps through the shortest path between `from` and
/// `to`. However, when these two angles are approximately `PI + k * TAU` apart
/// for any integer `k`, it's not obvious which way they lerp due to
/// floating-point precision errors. For example, `lerp_angle(0.0, PI, weight)`
/// lerps clockwise, while `lerp_angle(0.0, PI + 3.0 * TAU, weight)` lerps
/// counter-clockwise.
///
/// _Godot equivalent: @GlobalScope.lerp_angle()_
pub fn lerp_angle(from: f32, to: f32, weight: f32) -> f32 {
let difference = (to - from) % TAU;
let distance = (2.0 * difference) % TAU - difference;
from + distance * weight
}
Comment on lines +141 to +145
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this wrapping correctly?
Is the output in [0, TAU] or [-PI, PI] range or something else?

Some docs would be nice 🙂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just copied the code from godot, so i didn't super look into it closely.
https://github.com/godotengine/godot/blob/master/core/math/math_funcs.h#L389


/// Asserts that two values are approximately equal, using the provided `func`
/// for equality checking.
#[macro_export]
macro_rules! assert_eq_approx {
($a:expr, $b:expr, $func:expr $(,)?) => {
match ($a, $b) {
(a, b) => {
assert!(($func)(a,b), "\n left: {:?},\n right: {:?}", $a, $b);
}
}
};
($a:expr, $b:expr, $func:expr, $($t:tt)+) => {
match ($a, $b) {
(a, b) => {
assert!(($func)(a,b), "\n left: {:?},\n right: {:?},\n{}", $a, $b, format_args!($($t)+));
}
}
};
}

/// Asserts that two values are not approximately equal, using the provided
/// `func` for equality checking.
#[macro_export]
macro_rules! assert_ne_approx {
($a:expr, $b:expr, $func:expr $(, $($t:tt)*)?) => {
#[allow(clippy::redundant_closure_call)]
{
assert_eq_approx!($a, $b, |a,b| !($func)(a,b) $(, $($t)*)?)
}
};
}

#[cfg(test)]
mod test {
use std::f32::consts::{FRAC_PI_2, PI};

use super::*;

#[test]
fn equal_approx() {
assert_eq_approx!(1.0, 1.000001, is_equal_approx);
assert_ne_approx!(1.0, 2.0, is_equal_approx);
assert_eq_approx!(1.0, 1.000001, is_equal_approx, "Message {}", "formatted");
assert_ne_approx!(1.0, 2.0, is_equal_approx, "Message {}", "formatted");
}

#[test]
#[should_panic(expected = "I am inside format")]
fn eq_approx_fail_with_message() {
assert_eq_approx!(1.0, 2.0, is_equal_approx, "I am inside {}", "format");
}

#[test]
fn lerp_angle_test() {
assert_eq_approx!(lerp_angle(0.0, PI, 0.5), -FRAC_PI_2, is_equal_approx);
assert_eq_approx!(
lerp_angle(0.0, PI + 3.0 * TAU, 0.5),
FRAC_PI_2,
is_equal_approx
);
let angle = PI * 2.0 / 3.0;
assert_eq_approx!(
lerp_angle(-5.0 * TAU, angle + 3.0 * TAU, 0.5).sin(),
(angle / 2.0).sin(),
is_equal_approx
);
assert_eq_approx!(
lerp_angle(-5.0 * TAU, angle + 3.0 * TAU, 0.5).cos(),
(angle / 2.0).cos(),
is_equal_approx
);
}
}
28 changes: 24 additions & 4 deletions godot-core/src/builtin/vector2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
use std::fmt;
use std::ops::*;

use glam::Vec2;
use godot_ffi as sys;
use sys::{ffi_methods, GodotFfi};

use crate::builtin::math::*;
use crate::builtin::{inner, Vector2i};

use super::glam_helpers::GlamConv;
use super::glam_helpers::GlamType;

/// 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
Expand Down Expand Up @@ -97,6 +101,10 @@ impl Vector2 {
self.x / self.y
}

pub fn lerp(self, other: Self, weight: f32) -> Self {
Self::new(lerp(self.x, other.x, weight), lerp(self.y, other.y, weight))
}

pub fn bezier_derivative(self, control_1: Self, control_2: Self, end: Self, t: f32) -> Self {
let x = bezier_derivative(self.x, control_1.x, control_2.x, end.x, t);
let y = bezier_derivative(self.y, control_1.y, control_2.y, end.y, t);
Expand Down Expand Up @@ -199,10 +207,6 @@ impl Vector2 {
self.to_glam().length_squared()
}

pub fn lerp(self, to: Self, weight: f32) -> Self {
Self::from_glam(self.to_glam().lerp(to.to_glam(), weight))
}

pub fn limit_length(self, length: Option<f32>) -> Self {
Self::from_glam(self.to_glam().clamp_length_max(length.unwrap_or(1.0)))
}
Expand Down Expand Up @@ -323,3 +327,19 @@ pub enum Vector2Axis {
impl GodotFfi for Vector2Axis {
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
}

impl GlamType for Vec2 {
type Mapped = Vector2;

fn to_front(&self) -> Self::Mapped {
Vector2::new(self.x, self.y)
}

fn from_front(mapped: &Self::Mapped) -> Self {
Vec2::new(mapped.x, mapped.y)
}
}

impl GlamConv for Vector2 {
type Glam = Vec2;
}
33 changes: 33 additions & 0 deletions godot-core/src/builtin/vector3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ use std::ops::*;

use std::fmt;

use glam::f32::Vec3;
use glam::Vec3A;
use godot_ffi as sys;
use sys::{ffi_methods, GodotFfi};

use crate::builtin::math::*;
use crate::builtin::Vector3i;

use super::glam_helpers::GlamConv;
use super::glam_helpers::GlamType;

/// Vector used for 3D math using floating point coordinates.
///
/// 3-element structure that can be used to represent positions in 3D space or any other triple of
Expand Down Expand Up @@ -336,3 +341,31 @@ pub enum Vector3Axis {
impl GodotFfi for Vector3Axis {
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
}

impl GlamType for Vec3 {
type Mapped = Vector3;

fn to_front(&self) -> Self::Mapped {
Vector3::new(self.x, self.y, self.z)
}

fn from_front(mapped: &Self::Mapped) -> Self {
Vec3::new(mapped.x, mapped.y, mapped.z)
}
}

impl GlamType for Vec3A {
type Mapped = Vector3;

fn to_front(&self) -> Self::Mapped {
Vector3::new(self.x, self.y, self.z)
}

fn from_front(mapped: &Self::Mapped) -> Self {
Vec3A::new(mapped.x, mapped.y, mapped.z)
}
}
Comment on lines +357 to +367
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using Vec3A at the moment, so this is dead code.

Copy link
Member Author

@lilizoey lilizoey Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will be because the Transform3D will use Affine3A, since there is no Affine3, which uses Vec3A internally

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we then need to see if Vec3A <-> Vector3 conversions are not necessary all over the place 🤔 otherwise we might not gain much from using glam. But I guess it's a good start.


impl GlamConv for Vector3 {
type Glam = Vec3;
}
19 changes: 19 additions & 0 deletions godot-core/src/builtin/vector4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@

use std::fmt;

use glam::Vec4;
use godot_ffi as sys;
use sys::{ffi_methods, GodotFfi};

use crate::builtin::Vector4i;

use super::glam_helpers::{GlamConv, GlamType};

/// Vector used for 4D math using floating point coordinates.
///
/// 4-element structure that can be used to represent any quadruplet of numeric values.
Expand Down Expand Up @@ -107,3 +110,19 @@ pub enum Vector4Axis {
impl GodotFfi for Vector4Axis {
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
}

impl GlamType for Vec4 {
type Mapped = Vector4;

fn to_front(&self) -> Self::Mapped {
Vector4::new(self.x, self.y, self.z, self.w)
}

fn from_front(mapped: &Self::Mapped) -> Self {
Vec4::new(mapped.x, mapped.y, mapped.z, mapped.w)
}
}

impl GlamConv for Vector4 {
type Glam = Vec4;
}