Skip to content

Commit 00de6ac

Browse files
committed
Add basic impls of Rect2, Rect2i, Aabb, Plane
Add `Mul<X>` impls for `Transform2/3D` for the new types Add `min/max` functions for `Vector2/3`
1 parent afa2e59 commit 00de6ac

File tree

14 files changed

+651
-32
lines changed

14 files changed

+651
-32
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl Area2DVirtual for Player {
5353

5454
fn ready(&mut self) {
5555
let viewport = self.base.get_viewport_rect();
56-
self.screen_size = viewport.size();
56+
self.screen_size = viewport.size;
5757
self.base.hide();
5858
}
5959

godot-core/src/builtin/aabb.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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 godot_ffi as sys;
8+
use sys::{ffi_methods, GodotFfi};
9+
10+
use super::Vector3;
11+
12+
/// Axis-aligned bounding box in 3D space.
13+
///
14+
/// `Aabb` consists of a position, a size, and several utility functions. It is typically used for
15+
/// fast overlap tests.
16+
///
17+
/// Currently most methods are only available through [`InnerAabb`](super::inner::InnerAabb).
18+
///
19+
/// The 2D counterpart to `Aabb` is [`Rect2`](super::Rect2).
20+
#[derive(Default, Copy, Clone, PartialEq, Debug)]
21+
#[repr(C)]
22+
pub struct Aabb {
23+
pub position: Vector3,
24+
pub size: Vector3,
25+
}
26+
27+
impl Aabb {
28+
/// Create a new `Aabb` from a position and a size.
29+
///
30+
/// _Godot equivalent: `Aabb(Vector3 position, Vector3 size)`_
31+
#[inline]
32+
pub const fn new(position: Vector3, size: Vector3) -> Self {
33+
Self { position, size }
34+
}
35+
36+
/// Create a new `Aabb` with the first corner at `position` and opposite corner at `end`.
37+
#[inline]
38+
pub fn from_corners(position: Vector3, end: Vector3) -> Self {
39+
Self {
40+
position,
41+
size: position + end,
42+
}
43+
}
44+
45+
/// The end of the `Aabb` calculated as `position + size`.
46+
///
47+
/// _Godot equivalent: `Aabb.size` property_
48+
#[inline]
49+
pub fn end(&self) -> Vector3 {
50+
self.position + self.size
51+
}
52+
53+
/// Set size based on desired end-point.
54+
///
55+
/// _Godot equivalent: `Aabb.size` property_
56+
#[inline]
57+
pub fn set_end(&mut self, end: Vector3) {
58+
self.size = end - self.position
59+
}
60+
61+
/// Returns `true` if the two `Aabb`s are approximately equal, by calling `is_equal_approx` on
62+
/// `position` and `size`.
63+
///
64+
/// _Godot equivalent: `Aabb.is_equal_approx()`_
65+
#[inline]
66+
pub fn is_equal_approx(&self, other: &Self) -> bool {
67+
self.position.is_equal_approx(other.position) && self.size.is_equal_approx(other.size)
68+
}
69+
70+
/* Add in when `Aabb::abs()` is implemented.
71+
/// Assert that the size of the `Aabb` is not negative.
72+
///
73+
/// Certain functions will fail to give a correct result if the size is negative.
74+
#[inline]
75+
pub fn assert_nonnegative(&self) {
76+
assert!(
77+
self.size.x >= 0.0 && self.size.y >= 0.0 && self.size.z >= 0.0,
78+
"size {:?} is negative",
79+
self.size
80+
);
81+
}
82+
*/
83+
}
84+
85+
impl GodotFfi for Aabb {
86+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
87+
}

godot-core/src/builtin/mod.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
// Re-export macros.
3636
pub use crate::{array, dict, varray};
3737

38+
pub use aabb::*;
3839
pub use array_inner::{Array, VariantArray};
3940
pub use basis::*;
4041
pub use color::*;
@@ -43,8 +44,11 @@ pub use math::*;
4344
pub use node_path::*;
4445
pub use others::*;
4546
pub use packed_array::*;
47+
pub use plane::*;
4648
pub use projection::*;
4749
pub use quaternion::*;
50+
pub use rect2::*;
51+
pub use rect2i::*;
4852
pub use rid::*;
4953
pub use string::*;
5054
pub use string_name::*;
@@ -84,15 +88,19 @@ mod array_inner;
8488
#[path = "dictionary.rs"]
8589
mod dictionary_inner;
8690

91+
mod aabb;
8792
mod basis;
8893
mod color;
8994
mod glam_helpers;
9095
mod math;
9196
mod node_path;
9297
mod others;
9398
mod packed_array;
99+
mod plane;
94100
mod projection;
95101
mod quaternion;
102+
mod rect2;
103+
mod rect2i;
96104
mod rid;
97105
mod string;
98106
mod string_chars;
@@ -319,6 +327,17 @@ macro_rules! real {
319327
}};
320328
}
321329

330+
/// The side of a [`Rect2`] or [`Rect2i`].
331+
///
332+
/// _Godot equivalent: `@GlobalScope.Side`_
333+
#[repr(C)]
334+
pub enum RectSide {
335+
Left = 0,
336+
Top = 1,
337+
Right = 2,
338+
Bottom = 3,
339+
}
340+
322341
// ----------------------------------------------------------------------------------------------------------------------------------------------
323342

324343
/// Implementations of the `Export` trait for types where it can be done trivially.
@@ -352,7 +371,7 @@ mod export {
352371
impl_export_by_clone!(f32);
353372
impl_export_by_clone!(f64);
354373

355-
// impl_export_by_clone!(Aabb); // TODO uncomment once Aabb implements Clone
374+
impl_export_by_clone!(Aabb);
356375
impl_export_by_clone!(Basis);
357376
impl_export_by_clone!(Color);
358377
impl_export_by_clone!(GodotString);
@@ -366,11 +385,11 @@ mod export {
366385
impl_export_by_clone!(PackedStringArray);
367386
impl_export_by_clone!(PackedVector2Array);
368387
impl_export_by_clone!(PackedVector3Array);
369-
// impl_export_by_clone!(Plane); // TODO uncomment once Plane implements Clone
388+
impl_export_by_clone!(Plane);
370389
impl_export_by_clone!(Projection);
371390
impl_export_by_clone!(Quaternion);
372-
// impl_export_by_clone!(Rect2); // TODO uncomment once Rect2 implements Clone
373-
// impl_export_by_clone!(Rect2i); // TODO uncomment once Rect2i implements Clone
391+
impl_export_by_clone!(Rect2);
392+
impl_export_by_clone!(Rect2i);
374393
impl_export_by_clone!(Rid);
375394
impl_export_by_clone!(StringName);
376395
impl_export_by_clone!(Transform2D);

godot-core/src/builtin/others.rs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,16 @@
66

77
// Stub for various other built-in classes, which are currently incomplete, but whose types
88
// are required for codegen
9-
use crate::builtin::{inner, StringName, Vector2};
9+
use crate::builtin::{inner, StringName};
1010
use crate::obj::{Gd, GodotClass};
1111
use godot_ffi as sys;
1212
use sys::{ffi_methods, GodotFfi};
1313

1414
// TODO: Swap more inner math types with glam types
1515
// Note: ordered by enum ord in extension JSON
16-
impl_builtin_stub!(Rect2, OpaqueRect2);
17-
impl_builtin_stub!(Rect2i, OpaqueRect2i);
18-
impl_builtin_stub!(Plane, OpaquePlane);
19-
impl_builtin_stub!(Aabb, OpaqueAabb);
2016
impl_builtin_stub!(Callable, OpaqueCallable);
2117
impl_builtin_stub!(Signal, OpaqueSignal);
2218

23-
#[repr(C)]
24-
struct InnerRect {
25-
position: Vector2,
26-
size: Vector2,
27-
}
28-
29-
impl Rect2 {
30-
pub fn size(self) -> Vector2 {
31-
self.inner().size
32-
}
33-
34-
fn inner(self) -> InnerRect {
35-
unsafe { std::mem::transmute(self) }
36-
}
37-
}
38-
3919
impl Callable {
4020
pub fn from_object_method<T, S>(object: Gd<T>, method: S) -> Self
4121
where

godot-core/src/builtin/plane.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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::ops::Neg;
8+
9+
use godot_ffi as sys;
10+
use sys::{ffi_methods, GodotFfi};
11+
12+
use super::{is_equal_approx, real, Vector3};
13+
14+
/// 3D plane in [Hessian normal form](https://mathworld.wolfram.com/HessianNormalForm.html).
15+
///
16+
/// The Hessian form defines all points `point` which satisfy the equation
17+
/// `dot(normal, point) + d == 0`, where `normal` is the normal vector and `d`
18+
/// the distance from the origin.
19+
///
20+
/// Currently most methods are only available through [`InnerPlane`](super::inner::InnerPlane).
21+
///
22+
/// Note: almost all methods on `Plane` require that the `normal` vector have
23+
/// unit length and will panic if this invariant is violated. This is not separately
24+
/// annotated for each method.
25+
#[derive(Copy, Clone, PartialEq, Debug)]
26+
#[repr(C)]
27+
pub struct Plane {
28+
pub normal: Vector3,
29+
pub d: real,
30+
}
31+
32+
impl Plane {
33+
/// Creates a new `Plane` from the `normal` and the distance from the origin `d`.
34+
///
35+
/// # Panics
36+
/// In contrast to construction via `Plane { normal, d }`, this verifies that `normal` has unit length, and will
37+
/// panic if this is not the case.
38+
///
39+
/// _Godot equivalent: `Plane(Vector3 normal, float d)`_
40+
#[inline]
41+
pub fn new(unit_normal: Vector3, d: real) -> Self {
42+
let plane = Self {
43+
normal: unit_normal,
44+
d,
45+
};
46+
plane.assert_normalized();
47+
plane
48+
}
49+
50+
/// Create a new `Plane` through the origin from a normal.
51+
///
52+
/// # Panics
53+
/// See [`Self::new()`].
54+
///
55+
/// _Godot equivalent: `Plane(Vector3 normal)`_
56+
#[inline]
57+
pub fn from_normal_at_origin(normal: Vector3) -> Self {
58+
Self::new(normal, 0.0)
59+
}
60+
61+
/// Create a new `Plane` from a normal and a point in the plane.
62+
///
63+
/// # Panics
64+
/// See [`Self::new()`].
65+
///
66+
/// _Godot equivalent: `Plane(Vector3 normal, Vector3 point)`_
67+
#[inline]
68+
pub fn from_point_normal(point: Vector3, normal: Vector3) -> Self {
69+
Self::new(normal, normal.dot(point))
70+
}
71+
72+
/// Creates a new `Plane` from normal and origin distance.
73+
///
74+
/// `nx`, `ny`, `nz` are used for the `normal` vector.
75+
/// `d` is the distance from the origin.
76+
///
77+
/// # Panics
78+
/// See [`Self::new()`].
79+
///
80+
/// _Godot equivalent: `Plane(float a, float b, float c, float d)`_
81+
#[inline]
82+
pub fn from_components(nx: real, ny: real, nz: real, d: real) -> Self {
83+
Self::new(Vector3::new(nx, ny, nz), d)
84+
}
85+
86+
/// Creates a new `Plane` from three points, given in clockwise order.
87+
///
88+
/// # Panics
89+
/// Will panic if all three points are colinear.
90+
///
91+
/// _Godot equivalent: `Plane(Vector3 point1, Vector3 point2, Vector3 point3)`_
92+
#[inline]
93+
pub fn from_points(a: Vector3, b: Vector3, c: Vector3) -> Self {
94+
let normal = (a - c).cross(a - b);
95+
assert_ne!(
96+
normal,
97+
Vector3::ZERO,
98+
"points {a}, {b}, {c} are all colinear"
99+
);
100+
let normal = normal.normalized();
101+
Self {
102+
normal,
103+
d: normal.dot(a),
104+
}
105+
}
106+
107+
/// Returns `true` if the two `Plane`s are approximately equal, by calling `is_equal_approx` on
108+
/// `normal` and `d` or on `-normal` and `-d`.
109+
///
110+
/// _Godot equivalent: `Plane.is_equal_approx()`_
111+
#[inline]
112+
pub fn is_equal_approx(&self, other: &Self) -> bool {
113+
(self.normal.is_equal_approx(other.normal) && is_equal_approx(self.d, other.d))
114+
|| (self.normal.is_equal_approx(-other.normal) && is_equal_approx(self.d, -other.d))
115+
}
116+
117+
#[inline]
118+
fn assert_normalized(self) {
119+
assert!(
120+
self.normal.is_normalized(),
121+
"normal {:?} is not normalized",
122+
self.normal
123+
);
124+
}
125+
}
126+
127+
impl Neg for Plane {
128+
type Output = Plane;
129+
130+
/// Returns the negative value of the plane by flipping both the normal and the distance value. Meaning
131+
/// it creates a plane that is in the same place, but facing the opposite direction.
132+
fn neg(self) -> Self::Output {
133+
Self::new(-self.normal, -self.d)
134+
}
135+
}
136+
137+
impl GodotFfi for Plane {
138+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
139+
}
140+
141+
#[cfg(test)]
142+
mod test {
143+
use super::*;
144+
145+
/// Tests that none of the constructors panic for some simple planes.
146+
#[test]
147+
fn construction_succeeds() {
148+
let vec = Vector3::new(1.0, 2.0, 3.0).normalized();
149+
let Vector3 { x, y, z } = vec;
150+
let _ = Plane::new(vec, 5.0);
151+
let _ = Plane::from_normal_at_origin(vec);
152+
let _ = Plane::from_point_normal(Vector3::new(10.0, 20.0, 30.0), vec);
153+
let _ = Plane::from_components(x, y, z, 5.0);
154+
let _ = Plane::from_points(
155+
Vector3::new(1.0, 2.0, 3.0),
156+
Vector3::new(2.0, 3.0, 1.0),
157+
Vector3::new(3.0, 2.0, 1.0),
158+
);
159+
}
160+
161+
#[test]
162+
#[should_panic]
163+
fn new_unnormalized_panics() {
164+
let _ = Plane::new(Vector3::new(1.0, 2.0, 3.0), 5.0);
165+
}
166+
167+
#[test]
168+
#[should_panic]
169+
fn from_points_colinear_panics() {
170+
let _ = Plane::from_points(
171+
Vector3::new(0.0, 0.0, 0.0),
172+
Vector3::new(0.0, 0.0, 1.0),
173+
Vector3::new(0.0, 0.0, 2.0),
174+
);
175+
}
176+
}

0 commit comments

Comments
 (0)