Skip to content

Commit

Permalink
Merge #713
Browse files Browse the repository at this point in the history
713: Replace euclid with glam (proof-of-concept) r=toasteater a=Demindiro

I had some time to take a look at #594. I decided to go with `glam` since it compiles the fastest.

I went with the "front-end" approach as I believe that is the most flexible approach.

I did rename a few things (like `zero()` to `ZERO`, `quaternion()` to `new()`, ...) but that is easy to revert if required.

It doesn't seem like many changes are required. Wrapping all the methods in `glam` is easy to do with extensive use of `glam()` and `into()`. The crate does seem to miss implementations for a few types and methods like `Rect2` and `rotated`, so we'll have to implement those from scratch.

the `impl Mul/Div/Add/...`s for `Vector2` and `Vector3` are pretty much identical, maybe there is some way to reduce duplication?

Closes #594
Closes #670 (`Vector3` is fully implemented)

Co-authored-by: David Hoppenbrouwers <david@salt-inc.org>
Co-authored-by: toasteater <48371905+toasteater@users.noreply.github.com>
  • Loading branch information
3 people committed Mar 30, 2021
2 parents 9a703d2 + b1213f9 commit 8ec14eb
Show file tree
Hide file tree
Showing 29 changed files with 963 additions and 307 deletions.
3 changes: 1 addition & 2 deletions examples/dodge_the_creeps/src/main_scene.rs
Expand Up @@ -116,8 +116,7 @@ impl Main {
mob_owner
.set_linear_velocity(Vector2::new(rng.gen_range(x.min_speed..x.max_speed), 0.0));

mob_owner
.set_linear_velocity(mob_owner.linear_velocity().rotated(Angle { radians: d }));
mob_owner.set_linear_velocity(mob_owner.linear_velocity().rotated(d));

let hud = unsafe { owner.get_node_as_instance::<hud::Hud>("hud").unwrap() };

Expand Down
11 changes: 7 additions & 4 deletions examples/dodge_the_creeps/src/player.rs
Expand Up @@ -32,7 +32,7 @@ impl Player {
#[export]
fn _ready(&mut self, owner: &Area2D) {
let viewport = owner.get_viewport_rect();
self.screen_size = viewport.size.to_vector();
self.screen_size = viewport.size;
owner.hide();
}

Expand Down Expand Up @@ -61,7 +61,7 @@ impl Player {
}

if velocity.length() > 0.0 {
velocity = velocity.normalize() * self.speed;
velocity = velocity.normalized() * self.speed;

let animation;

Expand All @@ -82,8 +82,11 @@ impl Player {
}

let change = velocity * delta;
let position =
(owner.global_position() + change).clamp(Vector2::new(0.0, 0.0), self.screen_size);
let position = owner.global_position() + change;
let position = Vector2::new(
position.x.max(0.0).min(self.screen_size.x),
position.y.max(0.0).min(self.screen_size.y),
);
owner.set_global_position(position);
}

Expand Down
2 changes: 1 addition & 1 deletion examples/scene_create/Cargo.toml
Expand Up @@ -10,4 +10,4 @@ crate-type = ["cdylib"]

[dependencies]
gdnative = { path = "../../gdnative" }
euclid = "0.22.1"
glam = "0.13.0"
3 changes: 1 addition & 2 deletions examples/scene_create/src/lib.rs
@@ -1,4 +1,3 @@
use euclid::vec3;
use gdnative::prelude::*;

#[derive(Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -64,7 +63,7 @@ impl SceneCreate {

let x = (self.children_spawned % 10) as f32;
let z = (self.children_spawned / 10) as f32;
spatial.translate(vec3(-10.0 + x * 2.0, 0.0, -10.0 + z * 2.0));
spatial.translate(Vector3::new(-10.0 + x * 2.0, 0.0, -10.0 + z * 2.0));

// You need to parent the new scene under some node if you want it in the scene.
// We parent it under ourselves.
Expand Down
4 changes: 2 additions & 2 deletions gdnative-core/Cargo.toml
Expand Up @@ -20,12 +20,12 @@ type_tag_fallback = []
gdnative-sys = { path = "../gdnative-sys", version = "0.9.3" }
libc = "0.2"
approx = "0.4.0"
euclid = "0.22.1"
glam = "0.13.0"
indexmap = "1.6.0"
ahash = "0.7.0"

gdnative-impl-proc-macros = { path = "../impl/proc_macros", version = "=0.9.3" }

bitflags = { version = "1.2", optional = true }
parking_lot = { version = "0.11.0", optional = true }
atomic-take = "1.0.0"
atomic-take = "1.0.0"
92 changes: 53 additions & 39 deletions gdnative-core/src/core_types/geom/basis.rs
@@ -1,5 +1,5 @@
use crate::core_types::{Quat, Vector3};
use euclid::{approxeq::ApproxEq, default, Transform3D, UnknownUnit, Vector3D};
use crate::core_types::{IsEqualApprox, Quat, Vector3};
use core::ops::Mul;

/// A 3x3 matrix.
#[repr(C)]
Expand Down Expand Up @@ -96,7 +96,7 @@ impl Basis {
#[inline]
pub fn from_axis_angle(axis: &Vector3, phi: f32) -> Self {
assert!(
axis.length().approx_eq(&1.0),
axis.length().is_equal_approx(1.0),
"The axis Vector3 must be normalized."
);

Expand Down Expand Up @@ -147,7 +147,7 @@ impl Basis {
];

let det: f32 = x.x * co[0] + x.y * co[1] + x.z * co[2];
assert!(!det.approx_eq(&0.0), "Determinant was zero");
assert!(!det.is_equal_approx(0.0), "Determinant was zero");

let s: f32 = 1.0 / det;

Expand Down Expand Up @@ -210,7 +210,7 @@ impl Basis {
#[inline]
pub fn orthonormalize(&mut self) {
assert!(
!self.determinant().approx_eq(&0.0),
!self.determinant().is_equal_approx(0.0),
"Determinant should not be zero."
);

Expand All @@ -219,11 +219,11 @@ impl Basis {
let mut y = self.y();
let mut z = self.z();

x = x.normalize();
x = x.normalized();
y = y - x * (x.dot(y));
y = y.normalize();
y = y.normalized();
z = z - x * (x.dot(z)) - y * (y.dot(z));
z = z.normalize();
z = z.normalized();

self.set_x(x);
self.set_y(y);
Expand All @@ -241,23 +241,23 @@ impl Basis {

/// Returns `true` if `self` and `other` are approximately equal.
#[inline]
pub fn approx_eq(&self, other: &Basis) -> bool {
self.elements[0].approx_eq(&other.elements[0])
&& self.elements[1].approx_eq(&other.elements[1])
&& self.elements[2].approx_eq(&other.elements[2])
pub fn is_equal_approx(&self, other: &Basis) -> bool {
self.elements[0].is_equal_approx(other.elements[0])
&& self.elements[1].is_equal_approx(other.elements[1])
&& self.elements[2].is_equal_approx(other.elements[2])
}

#[inline]
fn is_orthogonal(&self) -> bool {
let identity = Self::identity();
let m = (*self) * self.transposed();
m.approx_eq(&identity)
m.is_equal_approx(&identity)
}

#[inline]
fn is_rotation(&self) -> bool {
let det = self.determinant();
det.approx_eq(&1.0) && self.is_orthogonal()
det.is_equal_approx(1.0) && self.is_orthogonal()
}

/// Multiplies the matrix from left by the rotation matrix: M -> R.M
Expand Down Expand Up @@ -328,9 +328,9 @@ impl Basis {
let k = (i + 2) % 3;

let elements_arr: [[f32; 3]; 3] = [
matrix.elements[0].to_array(),
matrix.elements[1].to_array(),
matrix.elements[2].to_array(),
*matrix.elements[0].as_ref(),
*matrix.elements[1].as_ref(),
*matrix.elements[2].as_ref(),
];

let mut s = (elements_arr[i][i] - elements_arr[j][j] - elements_arr[k][k] + 1.0).sqrt();
Expand All @@ -343,7 +343,7 @@ impl Basis {
}

let [a, b, c, r] = temp;
Quat::quaternion(a, b, c, r)
Quat::new(a, b, c, r)
}

/// Returns the scale of the matrix.
Expand Down Expand Up @@ -384,17 +384,17 @@ impl Basis {
/// See [`Basis::to_quat`](#method.to_quat) if you need a quaternion instead.
#[inline]
pub fn to_euler(&self) -> Vector3 {
let mut euler = Vector3::zero();
let mut euler = Vector3::ZERO;

let m12 = self.elements[1].z;
if m12 < 1.0 {
if m12 > -1.0 {
// is this a pure X rotation?
if self.elements[1].x.approx_eq(&0.0)
&& self.elements[0].y.approx_eq(&0.0)
&& self.elements[0].z.approx_eq(&0.0)
&& self.elements[2].x.approx_eq(&0.0)
&& self.elements[0].x.approx_eq(&1.0)
if self.elements[1].x.is_equal_approx(0.0)
&& self.elements[0].y.is_equal_approx(0.0)
&& self.elements[0].z.is_equal_approx(0.0)
&& self.elements[2].x.is_equal_approx(0.0)
&& self.elements[0].x.is_equal_approx(1.0)
{
// return the simplest form (human friendlier in editor and scripts)
euler.x = (-m12).atan2(self.elements[1].y);
Expand Down Expand Up @@ -471,6 +471,7 @@ impl Basis {
)
}

/*
/// Creates a `Basis` from the rotation and scaling of the provided transform.
#[inline]
pub fn from_transform(transform: &default::Transform3D<f32>) -> Basis {
Expand All @@ -494,6 +495,7 @@ impl Basis {
],
}
}
*/

/// Transposed dot product with the **X Axis** of the matrix.
#[inline]
Expand Down Expand Up @@ -580,6 +582,15 @@ impl core::ops::Mul<Basis> for Basis {
}
}

impl Mul<Vector3> for Basis {
type Output = Vector3;

#[inline]
fn mul(self, rhs: Self::Output) -> Self::Output {
Self::Output::new(self.tdotx(rhs), self.tdoty(rhs), self.tdotz(rhs))
}
}

#[cfg(test)]
#[allow(clippy::unreadable_literal)]
mod tests {
Expand Down Expand Up @@ -620,7 +631,7 @@ mod tests {
#[test]
fn set_is_sane() {
let mut basis = Basis {
elements: [Vector3::zero(), Vector3::zero(), Vector3::zero()],
elements: [Vector3::ZERO, Vector3::ZERO, Vector3::ZERO],
};

basis.set_x(Vector3::new(1.0, 4.0, 7.0));
Expand All @@ -634,7 +645,7 @@ mod tests {

fn test_inputs() -> (Basis, Basis) {
let v = Vector3::new(37.51756, 20.39467, 49.96816);
let vn = v.normalize();
let vn = v.normalized();
let b = Basis::from_euler(v);
let bn = Basis::from_euler(vn);
(b, bn)
Expand All @@ -644,14 +655,17 @@ mod tests {
fn determinant() {
let (b, _bn) = test_inputs();

assert!(b.determinant().approx_eq(&1.0), "Determinant should be 1.0");
assert!(
b.determinant().is_equal_approx(1.0),
"Determinant should be 1.0"
);
}

#[test]
fn euler() {
let (_b, bn) = test_inputs();

assert!(Vector3::new(0.57079, 0.310283, 0.760213).approx_eq(&bn.to_euler()));
assert!(Vector3::new(0.57079, 0.310283, 0.760213).is_equal_approx(bn.to_euler()));
}

#[test]
Expand All @@ -663,7 +677,7 @@ mod tests {
Vector3::new(-0.288147, 0.94041, 0.180557),
Vector3::new(-0.95445, -0.297299, 0.025257),
]);
assert!(expected.approx_eq(&b.orthonormalized()));
assert!(expected.is_equal_approx(&b.orthonormalized()));
}

#[test]
Expand All @@ -675,40 +689,40 @@ mod tests {
Vector3::new(0.012407, -0.040492, -0.007774),
Vector3::new(-0.682131, -0.212475, 0.018051),
]);
assert!(expected.approx_eq(&b.scaled(&Vector3::new(0.677813, -0.043058, 0.714685))));
assert!(expected.is_equal_approx(&b.scaled(&Vector3::new(0.677813, -0.043058, 0.714685))));
}

#[test]
fn rotated() {
let (b, _bn) = test_inputs();

let r = Vector3::new(-50.167156, 60.67781, -70.04305).normalize();
let r = Vector3::new(-50.167156, 60.67781, -70.04305).normalized();
let expected = Basis::from_elements([
Vector3::new(-0.676245, 0.113805, 0.727833),
Vector3::new(-0.467094, 0.697765, -0.54309),
Vector3::new(-0.569663, -0.707229, -0.418703),
]);
assert!(expected.approx_eq(&b.rotated(r, 1.0)));
assert!(expected.is_equal_approx(&b.rotated(r, 1.0)));
}

#[test]
fn to_quat() {
let (b, _bn) = test_inputs();

assert!(Quat::quaternion(-0.167156, 0.677813, -0.043058, 0.714685).approx_eq(&b.to_quat()));
assert!(Quat::new(-0.167156, 0.677813, -0.043058, 0.714685).is_equal_approx(&b.to_quat()));
}

#[test]
fn scale() {
let (b, _bn) = test_inputs();

assert!(Vector3::new(1.0, 1.0, 1.0).approx_eq(&b.to_scale()));
assert!(Vector3::new(1.0, 1.0, 1.0).is_equal_approx(b.to_scale()));
}

#[test]
fn approx_eq() {
let (b, _bn) = test_inputs();
assert!(!b.approx_eq(&Basis::from_euler(Vector3::new(37.517, 20.394, 49.968))));
assert!(!b.is_equal_approx(&Basis::from_euler(Vector3::new(37.517, 20.394, 49.968))));
}

#[test]
Expand All @@ -719,23 +733,23 @@ mod tests {
Vector3::new(-0.165055, 0.94041, -0.297299),
Vector3::new(0.98324, 0.180557, 0.025257),
]);
assert!(expected.approx_eq(&b.transposed()));
assert!(expected.is_equal_approx(&b.transposed()));
}

#[test]
fn xform() {
let (b, _bn) = test_inputs();

assert!(Vector3::new(-0.273471, 0.478102, -0.690386)
.approx_eq(&b.xform(Vector3::new(0.5, 0.7, -0.2))));
.is_equal_approx(b.xform(Vector3::new(0.5, 0.7, -0.2))));
}

#[test]
fn xform_inv() {
let (b, _bn) = test_inputs();

assert!(Vector3::new(-0.884898, -0.460316, 0.071165)
.approx_eq(&b.xform_inv(Vector3::new(0.077431, -0.165055, 0.98324))));
.is_equal_approx(b.xform_inv(Vector3::new(0.077431, -0.165055, 0.98324))));
}

#[test]
Expand All @@ -747,6 +761,6 @@ mod tests {
Vector3::new(-0.165055, 0.94041, -0.297299),
Vector3::new(0.98324, 0.180557, 0.025257),
]);
assert!(expected.approx_eq(&b.inverted()));
assert!(expected.is_equal_approx(&b.inverted()));
}
}
12 changes: 0 additions & 12 deletions gdnative-core/src/core_types/geom/mod.rs
Expand Up @@ -5,18 +5,6 @@ mod basis;
mod plane;
mod transform;

pub type Vector3 = euclid::default::Vector3D<f32>;
pub type Vector2 = euclid::default::Vector2D<f32>;
pub type Transform2D = euclid::default::Transform2D<f32>;
pub type Quat = euclid::default::Rotation3D<f32>;
pub type Size2 = euclid::default::Size2D<f32>;
pub type Rect2 = euclid::default::Rect<f32>;
pub type Angle = euclid::Angle<f32>;
pub type Point3 = euclid::default::Point3D<f32>;
pub type Point2 = euclid::default::Point2D<f32>;
pub type Rotation2D = euclid::default::Rotation2D<f32>;
pub type Rotation3D = euclid::default::Rotation3D<f32>;

pub use self::aabb::Aabb;
pub use self::basis::Basis;
pub use self::plane::Plane;
Expand Down

0 comments on commit 8ec14eb

Please sign in to comment.