Skip to content

Commit 6276b8f

Browse files
committed
Projection{Eye|Plane}::try_from_ord(), Projection documentation
1 parent 6fd33dc commit 6276b8f

File tree

1 file changed

+77
-67
lines changed

1 file changed

+77
-67
lines changed

godot-core/src/builtin/projection.rs

+77-67
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@ use std::ops::Mul;
1717
use super::meta::impl_godot_as_self;
1818
use super::{Aabb, Rect2, Vector3};
1919

20-
/// A 4x4 matrix used for 3D projective transformations. It can represent
21-
/// transformations such as translation, rotation, scaling, shearing, and
22-
/// perspective division. It consists of four Vector4 columns.
20+
/// A 4x4 matrix used for 3D projective transformations.
2321
///
24-
/// For purely linear transformations (translation, rotation, and scale), it is
25-
/// recommended to use Transform3D, as it is more performant and has a lower
26-
/// memory footprint.
22+
/// `Projection` can represent transformations such as translation, rotation, scaling, shearing, and perspective division.
23+
/// It consists of four [`Vector4`] columns.
2724
///
28-
/// Used internally as Camera3D's projection matrix.
25+
/// For purely linear transformations (translation, rotation, and scale), it is recommended to use [`Transform3D`], as that is
26+
/// more performant and has a lower memory footprint.
2927
///
30-
/// Note: The current implementation largely makes calls to godot for its
31-
/// methods and as such are not as performant as other types.
28+
/// Used internally as `Camera3D`'s projection matrix.
3229
#[derive(Copy, Clone, PartialEq, Debug)]
3330
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3431
#[repr(C)]
@@ -40,14 +37,10 @@ pub struct Projection {
4037
impl Projection {
4138
/// A Projection with no transformation defined. When applied to other data
4239
/// structures, no transformation is performed.
43-
///
44-
/// _Godot equivalent: Projection.IDENTITY_
4540
pub const IDENTITY: Self = Self::from_diagonal(1.0, 1.0, 1.0, 1.0);
4641

4742
/// A Projection with all values initialized to 0. When applied to other
4843
/// data structures, they will be zeroed.
49-
///
50-
/// _Godot equivalent: Projection.ZERO_
5144
pub const ZERO: Self = Self::from_diagonal(0.0, 0.0, 0.0, 0.0);
5245

5346
/// Create a new projection from a list of column vectors.
@@ -67,7 +60,7 @@ impl Projection {
6760

6861
/// Create a matrix from four column vectors.
6962
///
70-
/// _Godot equivalent: Projection(Vector4 x_axis, Vector4 y_axis, Vector4 z_axis, Vector4 w_axis)_
63+
/// _Godot equivalent: `Projection(Vector4 x_axis, Vector4 y_axis, Vector4 z_axis, Vector4 w_axis)`_
7164
pub const fn from_cols(x: Vector4, y: Vector4, z: Vector4, w: Vector4) -> Self {
7265
Self { cols: [x, y, z, w] }
7366
}
@@ -76,7 +69,7 @@ impl Projection {
7669
/// -1 to 1 to one that ranges from 0 to 1, and flips the projected
7770
/// positions vertically, according to flip_y.
7871
///
79-
/// _Godot equivalent: Projection.create_depth_correction()_
72+
/// _Godot equivalent: `Projection.create_depth_correction()`_
8073
pub fn create_depth_correction(flip_y: bool) -> Self {
8174
Self::from_cols(
8275
Vector4::new(1.0, 0.0, 0.0, 0.0),
@@ -89,7 +82,7 @@ impl Projection {
8982
/// Creates a new Projection that scales a given projection to fit around
9083
/// a given AABB in projection space.
9184
///
92-
/// _Godot equivalent: Projection.create_fit_aabb()_
85+
/// _Godot equivalent: `Projection.create_fit_aabb()`_
9386
pub fn create_fit_aabb(aabb: Aabb) -> Self {
9487
let translate_unscaled = -2.0 * aabb.position - aabb.size; // -(start+end)
9588

@@ -108,7 +101,7 @@ impl Projection {
108101
/// display with the given X:Y aspect ratio, distance between eyes, display
109102
/// width, distance to lens, oversampling factor, and depth clipping planes.
110103
///
111-
/// _Godot equivalent: Projection.create_for_hmd()_
104+
/// _Godot equivalent: `Projection.create_for_hmd()`_
112105
#[allow(clippy::too_many_arguments)]
113106
pub fn create_for_hmd(
114107
eye: ProjectionEye,
@@ -137,7 +130,7 @@ impl Projection {
137130
/// Creates a new Projection that projects positions in a frustum with the
138131
/// given clipping planes.
139132
///
140-
/// _Godot equivalent: Projection.create_frustum()_
133+
/// _Godot equivalent: `Projection.create_frustum()`_
141134
pub fn create_frustum(
142135
left: real,
143136
right: real,
@@ -171,7 +164,7 @@ impl Projection {
171164
/// `flip_fov` determines whether the projection's field of view is flipped
172165
/// over its diagonal.
173166
///
174-
/// _Godot equivalent: Projection.create_frustum_aspect()_
167+
/// _Godot equivalent: `Projection.create_frustum_aspect()`_
175168
pub fn create_frustum_aspect(
176169
size: real,
177170
aspect: real,
@@ -204,7 +197,7 @@ impl Projection {
204197

205198
/// Creates a new Projection that projects positions into the given Rect2.
206199
///
207-
/// _Godot equivalent: Projection.create_light_atlas_rect()_
200+
/// _Godot equivalent: `Projection.create_light_atlas_rect()`_
208201
pub fn create_light_atlas_rect(rect: Rect2) -> Self {
209202
Self::from_cols(
210203
Vector4::new(rect.size.x, 0.0, 0.0, 0.0),
@@ -217,7 +210,7 @@ impl Projection {
217210
/// Creates a new Projection that projects positions using an orthogonal
218211
/// projection with the given clipping planes.
219212
///
220-
/// _Godot equivalent: Projection.create_orthogonal()_
213+
/// _Godot equivalent: `Projection.create_orthogonal()`_
221214
pub fn create_orthogonal(
222215
left: real,
223216
right: real,
@@ -235,7 +228,7 @@ impl Projection {
235228
/// `flip_fov` determines whether the projection's field of view is flipped
236229
/// over its diagonal.
237230
///
238-
/// _Godot equivalent: Projection.create_orthogonal_aspect()_
231+
/// _Godot equivalent: `Projection.create_orthogonal_aspect()`_
239232
pub fn create_orthogonal_aspect(
240233
size: real,
241234
aspect: real,
@@ -261,7 +254,7 @@ impl Projection {
261254
/// `flip_fov` determines whether the projection's field of view is flipped
262255
/// over its diagonal.
263256
///
264-
/// _Godot equivalent: Projection.create_perspective()_
257+
/// _Godot equivalent: `Projection.create_perspective()`_
265258
pub fn create_perspective(
266259
fov_y: real,
267260
aspect: real,
@@ -286,7 +279,7 @@ impl Projection {
286279
/// `flip_fov` determines whether the projection's field of view is flipped
287280
/// over its diagonal.
288281
///
289-
/// _Godot equivalent: Projection.create_perspective_hmd()_
282+
/// _Godot equivalent: `Projection.create_perspective_hmd()`_
290283
#[allow(clippy::too_many_arguments)]
291284
pub fn create_perspective_hmd(
292285
fov_y: real,
@@ -326,116 +319,105 @@ impl Projection {
326319
ret
327320
}
328321

329-
/// Return the determinant of the matrix.
322+
/// Returns the vertical field of view of a projection (in degrees) which
323+
/// has the given horizontal field of view (in degrees) and aspect ratio.
330324
///
331-
/// _Godot equivalent: Projection.determinant()_
325+
/// _Godot equivalent: `Projection.get_fovy()`_
326+
#[doc(alias = "get_fovy")]
327+
pub fn create_fovy(fov_x: real, aspect: real) -> real {
328+
let half_angle_fov_x = f64::to_radians(fov_x.as_f64() * 0.5);
329+
let vertical_transform = f64::atan(aspect.as_f64() * f64::tan(half_angle_fov_x));
330+
let full_angle_fov_y = f64::to_degrees(vertical_transform * 2.0);
331+
332+
real::from_f64(full_angle_fov_y)
333+
}
334+
335+
/// Return the determinant of the matrix.
332336
pub fn determinant(&self) -> real {
333337
self.glam(|mat| mat.determinant())
334338
}
335339

336-
/// Returns a copy of this Projection with the signs of the values of the Y
337-
/// column flipped.
338-
///
339-
/// _Godot equivalent: Projection.flipped_y()_
340+
/// Returns a copy of this projection, with the signs of the values of the Y column flipped.
340341
pub fn flipped_y(self) -> Self {
341342
let [x, y, z, w] = self.cols;
342343
Self::from_cols(x, -y, z, w)
343344
}
344345

345346
/// Returns the X:Y aspect ratio of this Projection's viewport.
346-
///
347-
/// _Godot equivalent: Projection.get_aspect()_
348347
pub fn aspect(&self) -> real {
349348
real::from_f64(self.as_inner().get_aspect())
350349
}
351350

352351
/// Returns the dimensions of the far clipping plane of the projection,
353352
/// divided by two.
354-
///
355-
/// _Godot equivalent: Projection.get_far_plane_half_extents()_
356353
pub fn far_plane_half_extents(&self) -> Vector2 {
357354
self.as_inner().get_far_plane_half_extents()
358355
}
359356

360357
/// Returns the horizontal field of view of the projection (in degrees).
361358
///
362-
/// _Godot equivalent: Projection.get_fov()_
359+
/// _Godot equivalent: `Projection.get_fov()`_
363360
pub fn fov(&self) -> real {
364361
real::from_f64(self.as_inner().get_fov())
365362
}
366363

367-
/// Returns the vertical field of view of a projection (in degrees) which
368-
/// has the given horizontal field of view (in degrees) and aspect ratio.
369-
///
370-
/// _Godot equivalent: Projection.get_fovy()_
371-
#[doc(alias = "get_fovy")]
372-
pub fn create_fovy(fov_x: real, aspect: real) -> real {
373-
let half_angle_fov_x = f64::to_radians(fov_x.as_f64() * 0.5);
374-
let vertical_transform = f64::atan(aspect.as_f64() * f64::tan(half_angle_fov_x));
375-
let full_angle_fov_y = f64::to_degrees(vertical_transform * 2.0);
376-
377-
real::from_f64(full_angle_fov_y)
378-
}
379-
380364
/// Returns the factor by which the visible level of detail is scaled by
381365
/// this Projection.
382366
///
383-
/// _Godot equivalent: Projection.get_lod_multiplier()_
367+
/// _Godot equivalent: `Projection.get_lod_multiplier()`_
384368
pub fn lod_multiplier(&self) -> real {
385369
real::from_f64(self.as_inner().get_lod_multiplier())
386370
}
387371

388372
/// Returns the number of pixels with the given pixel width displayed per
389373
/// meter, after this Projection is applied.
390374
///
391-
/// _Godot equivalent: Projection.get_pixels_per_meter()_
392-
pub fn pixels_per_meter(&self, pixel_width: i64) -> i64 {
375+
/// _Godot equivalent: `Projection.get_pixels_per_meter()`_
376+
pub fn get_pixels_per_meter(&self, pixel_width: i64) -> i64 {
393377
self.as_inner().get_pixels_per_meter(pixel_width)
394378
}
395379

396380
/// Returns the clipping plane of this Projection whose index is given by
397381
/// plane.
398382
///
399-
/// _Godot equivalent: Projection.get_projection_plane()_
400-
pub fn projection_plane(&self, plane: ProjectionPlane) -> Plane {
383+
/// _Godot equivalent: `Projection.get_projection_plane()`_
384+
pub fn get_projection_plane(&self, plane: ProjectionPlane) -> Plane {
401385
self.as_inner().get_projection_plane(plane as i64)
402386
}
403387

404388
/// Returns the dimensions of the viewport plane that this Projection
405389
/// projects positions onto, divided by two.
406390
///
407-
/// _Godot equivalent: Projection.get_viewport_half_extents()_
391+
/// _Godot equivalent: `Projection.get_viewport_half_extents()`_
408392
pub fn viewport_half_extents(&self) -> Vector2 {
409393
self.as_inner().get_viewport_half_extents()
410394
}
411395

412396
/// Returns the distance for this Projection beyond which positions are
413397
/// clipped.
414398
///
415-
/// _Godot equivalent: Projection.get_z_far()_
399+
/// _Godot equivalent: `Projection.get_z_far()`_
416400
pub fn z_far(&self) -> real {
417401
real::from_f64(self.as_inner().get_z_far())
418402
}
419403

420404
/// Returns the distance for this Projection before which positions are
421405
/// clipped.
422406
///
423-
/// _Godot equivalent: Projection.get_z_near()_
407+
/// _Godot equivalent: `Projection.get_z_near()`_
424408
pub fn z_near(&self) -> real {
425409
real::from_f64(self.as_inner().get_z_near())
426410
}
427411

428412
/// Returns a Projection that performs the inverse of this Projection's
429413
/// projective transformation.
430-
///
431-
/// _Godot equivalent: Projection.inverse()_
432414
pub fn inverse(self) -> Self {
433415
self.glam(|mat| mat.inverse())
434416
}
435417

436418
/// Returns `true` if this Projection performs an orthogonal projection.
437419
///
438-
/// _Godot equivalent: Projection.is_orthogonal()_
420+
/// _Godot equivalent: `Projection.is_orthogonal()`_
439421
pub fn is_orthogonal(&self) -> bool {
440422
self.cols[3].w == 1.0
441423

@@ -450,7 +432,7 @@ impl Projection {
450432
/// Returns a Projection with the X and Y values from the given [`Vector2`]
451433
/// added to the first and second values of the final column respectively.
452434
///
453-
/// _Godot equivalent: Projection.jitter_offseted()_
435+
/// _Godot equivalent: `Projection.jitter_offseted()`_
454436
#[must_use]
455437
pub fn jitter_offset(&self, offset: Vector2) -> Self {
456438
Self::from_cols(
@@ -466,7 +448,7 @@ impl Projection {
466448
///
467449
/// Note: The original Projection must be a perspective projection.
468450
///
469-
/// _Godot equivalent: Projection.perspective_znear_adjusted()_
451+
/// _Godot equivalent: `Projection.perspective_znear_adjusted()`_
470452
pub fn perspective_znear_adjusted(&self, new_znear: real) -> Self {
471453
self.as_inner()
472454
.perspective_znear_adjusted(new_znear.as_f64())
@@ -545,8 +527,7 @@ impl GlamConv for Projection {
545527
type Glam = RMat4;
546528
}
547529

548-
// SAFETY:
549-
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
530+
// SAFETY: This type is represented as `Self` in Godot, so `*mut Self` is sound.
550531
unsafe impl GodotFfi for Projection {
551532
fn variant_type() -> sys::VariantType {
552533
sys::VariantType::Projection
@@ -557,7 +538,9 @@ unsafe impl GodotFfi for Projection {
557538

558539
impl_godot_as_self!(Projection);
559540

560-
/// A projections clipping plane.
541+
/// A projection's clipping plane.
542+
///
543+
/// See [Godot docs about `Projection` constants](https://docs.godotengine.org/en/stable/classes/class_projection.html#constants).
561544
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
562545
#[repr(C)]
563546
pub enum ProjectionPlane {
@@ -569,33 +552,60 @@ pub enum ProjectionPlane {
569552
Bottom = 5,
570553
}
571554

572-
/// The eye to create a projection for, when creating a projection adjusted
573-
/// for head-mounted displays.
555+
impl ProjectionPlane {
556+
/// Convert from one of GDScript's `Projection.PLANE_*` integer constants.
557+
pub fn try_from_ord(ord: i64) -> Option<Self> {
558+
match ord {
559+
0 => Some(Self::Near),
560+
1 => Some(Self::Far),
561+
2 => Some(Self::Left),
562+
3 => Some(Self::Top),
563+
4 => Some(Self::Right),
564+
5 => Some(Self::Bottom),
565+
_ => None,
566+
}
567+
}
568+
}
569+
570+
/// The eye to create a projection for, when creating a projection adjusted for head-mounted displays.
574571
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
575572
#[repr(C)]
576573
pub enum ProjectionEye {
577574
Left = 1,
578575
Right = 2,
579576
}
580577

578+
impl ProjectionEye {
579+
/// Convert from numbers `1` and `2`.
580+
pub fn try_from_ord(ord: i64) -> Option<Self> {
581+
match ord {
582+
1 => Some(Self::Left),
583+
2 => Some(Self::Right),
584+
_ => None,
585+
}
586+
}
587+
}
588+
581589
impl std::fmt::Display for Projection {
582590
/// Formats `Projection` to match Godot's string representation.
583591
///
584592
/// # Example
585593
/// ```
586-
/// use godot::prelude::*;
594+
/// # use godot::prelude::*;
587595
/// let proj = Projection::new([
588596
/// Vector4::new(1.0, 2.5, 1.0, 0.5),
589597
/// Vector4::new(0.0, 1.5, 2.0, 0.5),
590598
/// Vector4::new(0.0, 0.0, 3.0, 2.5),
591599
/// Vector4::new(3.0, 1.0, 4.0, 1.5),
592600
/// ]);
601+
///
593602
/// const FMT_RESULT: &str = r"
594603
/// 1, 0, 0, 3
595604
/// 2.5, 1.5, 0, 1
596605
/// 1, 2, 3, 4
597606
/// 0.5, 0.5, 2.5, 1.5
598607
/// ";
608+
///
599609
/// assert_eq!(format!("{}", proj), FMT_RESULT);
600610
/// ```
601611
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

0 commit comments

Comments
 (0)