@@ -17,18 +17,15 @@ use std::ops::Mul;
17
17
use super :: meta:: impl_godot_as_self;
18
18
use super :: { Aabb , Rect2 , Vector3 } ;
19
19
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.
23
21
///
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. It is used internally as `Camera3D`'s projection matrix.
27
24
///
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.
29
27
///
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
+ /// This builtin comes with two related types [`ProjectionEye`] and [`ProjectionPlane`], that are type-safe pendants to Godot's integers.
32
29
#[ derive( Copy , Clone , PartialEq , Debug ) ]
33
30
#[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
34
31
#[ repr( C ) ]
@@ -40,14 +37,10 @@ pub struct Projection {
40
37
impl Projection {
41
38
/// A Projection with no transformation defined. When applied to other data
42
39
/// structures, no transformation is performed.
43
- ///
44
- /// _Godot equivalent: Projection.IDENTITY_
45
40
pub const IDENTITY : Self = Self :: from_diagonal ( 1.0 , 1.0 , 1.0 , 1.0 ) ;
46
41
47
42
/// A Projection with all values initialized to 0. When applied to other
48
43
/// data structures, they will be zeroed.
49
- ///
50
- /// _Godot equivalent: Projection.ZERO_
51
44
pub const ZERO : Self = Self :: from_diagonal ( 0.0 , 0.0 , 0.0 , 0.0 ) ;
52
45
53
46
/// Create a new projection from a list of column vectors.
@@ -67,7 +60,7 @@ impl Projection {
67
60
68
61
/// Create a matrix from four column vectors.
69
62
///
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)` _
71
64
pub const fn from_cols ( x : Vector4 , y : Vector4 , z : Vector4 , w : Vector4 ) -> Self {
72
65
Self { cols : [ x, y, z, w] }
73
66
}
@@ -76,7 +69,7 @@ impl Projection {
76
69
/// -1 to 1 to one that ranges from 0 to 1, and flips the projected
77
70
/// positions vertically, according to flip_y.
78
71
///
79
- /// _Godot equivalent: Projection.create_depth_correction()_
72
+ /// _Godot equivalent: ` Projection.create_depth_correction()` _
80
73
pub fn create_depth_correction ( flip_y : bool ) -> Self {
81
74
Self :: from_cols (
82
75
Vector4 :: new ( 1.0 , 0.0 , 0.0 , 0.0 ) ,
@@ -89,7 +82,7 @@ impl Projection {
89
82
/// Creates a new Projection that scales a given projection to fit around
90
83
/// a given AABB in projection space.
91
84
///
92
- /// _Godot equivalent: Projection.create_fit_aabb()_
85
+ /// _Godot equivalent: ` Projection.create_fit_aabb()` _
93
86
pub fn create_fit_aabb ( aabb : Aabb ) -> Self {
94
87
let translate_unscaled = -2.0 * aabb. position - aabb. size ; // -(start+end)
95
88
@@ -108,7 +101,7 @@ impl Projection {
108
101
/// display with the given X:Y aspect ratio, distance between eyes, display
109
102
/// width, distance to lens, oversampling factor, and depth clipping planes.
110
103
///
111
- /// _Godot equivalent: Projection.create_for_hmd()_
104
+ /// _Godot equivalent: ` Projection.create_for_hmd()` _
112
105
#[ allow( clippy:: too_many_arguments) ]
113
106
pub fn create_for_hmd (
114
107
eye : ProjectionEye ,
@@ -137,7 +130,7 @@ impl Projection {
137
130
/// Creates a new Projection that projects positions in a frustum with the
138
131
/// given clipping planes.
139
132
///
140
- /// _Godot equivalent: Projection.create_frustum()_
133
+ /// _Godot equivalent: ` Projection.create_frustum()` _
141
134
pub fn create_frustum (
142
135
left : real ,
143
136
right : real ,
@@ -171,7 +164,7 @@ impl Projection {
171
164
/// `flip_fov` determines whether the projection's field of view is flipped
172
165
/// over its diagonal.
173
166
///
174
- /// _Godot equivalent: Projection.create_frustum_aspect()_
167
+ /// _Godot equivalent: ` Projection.create_frustum_aspect()` _
175
168
pub fn create_frustum_aspect (
176
169
size : real ,
177
170
aspect : real ,
@@ -204,7 +197,7 @@ impl Projection {
204
197
205
198
/// Creates a new Projection that projects positions into the given Rect2.
206
199
///
207
- /// _Godot equivalent: Projection.create_light_atlas_rect()_
200
+ /// _Godot equivalent: ` Projection.create_light_atlas_rect()` _
208
201
pub fn create_light_atlas_rect ( rect : Rect2 ) -> Self {
209
202
Self :: from_cols (
210
203
Vector4 :: new ( rect. size . x , 0.0 , 0.0 , 0.0 ) ,
@@ -217,7 +210,7 @@ impl Projection {
217
210
/// Creates a new Projection that projects positions using an orthogonal
218
211
/// projection with the given clipping planes.
219
212
///
220
- /// _Godot equivalent: Projection.create_orthogonal()_
213
+ /// _Godot equivalent: ` Projection.create_orthogonal()` _
221
214
pub fn create_orthogonal (
222
215
left : real ,
223
216
right : real ,
@@ -235,7 +228,7 @@ impl Projection {
235
228
/// `flip_fov` determines whether the projection's field of view is flipped
236
229
/// over its diagonal.
237
230
///
238
- /// _Godot equivalent: Projection.create_orthogonal_aspect()_
231
+ /// _Godot equivalent: ` Projection.create_orthogonal_aspect()` _
239
232
pub fn create_orthogonal_aspect (
240
233
size : real ,
241
234
aspect : real ,
@@ -261,7 +254,7 @@ impl Projection {
261
254
/// `flip_fov` determines whether the projection's field of view is flipped
262
255
/// over its diagonal.
263
256
///
264
- /// _Godot equivalent: Projection.create_perspective()_
257
+ /// _Godot equivalent: ` Projection.create_perspective()` _
265
258
pub fn create_perspective (
266
259
fov_y : real ,
267
260
aspect : real ,
@@ -286,7 +279,7 @@ impl Projection {
286
279
/// `flip_fov` determines whether the projection's field of view is flipped
287
280
/// over its diagonal.
288
281
///
289
- /// _Godot equivalent: Projection.create_perspective_hmd()_
282
+ /// _Godot equivalent: ` Projection.create_perspective_hmd()` _
290
283
#[ allow( clippy:: too_many_arguments) ]
291
284
pub fn create_perspective_hmd (
292
285
fov_y : real ,
@@ -326,116 +319,105 @@ impl Projection {
326
319
ret
327
320
}
328
321
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.
330
324
///
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.
332
336
pub fn determinant ( & self ) -> real {
333
337
self . glam ( |mat| mat. determinant ( ) )
334
338
}
335
339
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.
340
341
pub fn flipped_y ( self ) -> Self {
341
342
let [ x, y, z, w] = self . cols ;
342
343
Self :: from_cols ( x, -y, z, w)
343
344
}
344
345
345
346
/// Returns the X:Y aspect ratio of this Projection's viewport.
346
- ///
347
- /// _Godot equivalent: Projection.get_aspect()_
348
347
pub fn aspect ( & self ) -> real {
349
348
real:: from_f64 ( self . as_inner ( ) . get_aspect ( ) )
350
349
}
351
350
352
351
/// Returns the dimensions of the far clipping plane of the projection,
353
352
/// divided by two.
354
- ///
355
- /// _Godot equivalent: Projection.get_far_plane_half_extents()_
356
353
pub fn far_plane_half_extents ( & self ) -> Vector2 {
357
354
self . as_inner ( ) . get_far_plane_half_extents ( )
358
355
}
359
356
360
357
/// Returns the horizontal field of view of the projection (in degrees).
361
358
///
362
- /// _Godot equivalent: Projection.get_fov()_
359
+ /// _Godot equivalent: ` Projection.get_fov()` _
363
360
pub fn fov ( & self ) -> real {
364
361
real:: from_f64 ( self . as_inner ( ) . get_fov ( ) )
365
362
}
366
363
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
-
380
364
/// Returns the factor by which the visible level of detail is scaled by
381
365
/// this Projection.
382
366
///
383
- /// _Godot equivalent: Projection.get_lod_multiplier()_
367
+ /// _Godot equivalent: ` Projection.get_lod_multiplier()` _
384
368
pub fn lod_multiplier ( & self ) -> real {
385
369
real:: from_f64 ( self . as_inner ( ) . get_lod_multiplier ( ) )
386
370
}
387
371
388
372
/// Returns the number of pixels with the given pixel width displayed per
389
373
/// meter, after this Projection is applied.
390
374
///
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 {
393
377
self . as_inner ( ) . get_pixels_per_meter ( pixel_width)
394
378
}
395
379
396
380
/// Returns the clipping plane of this Projection whose index is given by
397
381
/// plane.
398
382
///
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 {
401
385
self . as_inner ( ) . get_projection_plane ( plane as i64 )
402
386
}
403
387
404
388
/// Returns the dimensions of the viewport plane that this Projection
405
389
/// projects positions onto, divided by two.
406
390
///
407
- /// _Godot equivalent: Projection.get_viewport_half_extents()_
391
+ /// _Godot equivalent: ` Projection.get_viewport_half_extents()` _
408
392
pub fn viewport_half_extents ( & self ) -> Vector2 {
409
393
self . as_inner ( ) . get_viewport_half_extents ( )
410
394
}
411
395
412
396
/// Returns the distance for this Projection beyond which positions are
413
397
/// clipped.
414
398
///
415
- /// _Godot equivalent: Projection.get_z_far()_
399
+ /// _Godot equivalent: ` Projection.get_z_far()` _
416
400
pub fn z_far ( & self ) -> real {
417
401
real:: from_f64 ( self . as_inner ( ) . get_z_far ( ) )
418
402
}
419
403
420
404
/// Returns the distance for this Projection before which positions are
421
405
/// clipped.
422
406
///
423
- /// _Godot equivalent: Projection.get_z_near()_
407
+ /// _Godot equivalent: ` Projection.get_z_near()` _
424
408
pub fn z_near ( & self ) -> real {
425
409
real:: from_f64 ( self . as_inner ( ) . get_z_near ( ) )
426
410
}
427
411
428
412
/// Returns a Projection that performs the inverse of this Projection's
429
413
/// projective transformation.
430
- ///
431
- /// _Godot equivalent: Projection.inverse()_
432
414
pub fn inverse ( self ) -> Self {
433
415
self . glam ( |mat| mat. inverse ( ) )
434
416
}
435
417
436
418
/// Returns `true` if this Projection performs an orthogonal projection.
437
419
///
438
- /// _Godot equivalent: Projection.is_orthogonal()_
420
+ /// _Godot equivalent: ` Projection.is_orthogonal()` _
439
421
pub fn is_orthogonal ( & self ) -> bool {
440
422
self . cols [ 3 ] . w == 1.0
441
423
@@ -450,7 +432,7 @@ impl Projection {
450
432
/// Returns a Projection with the X and Y values from the given [`Vector2`]
451
433
/// added to the first and second values of the final column respectively.
452
434
///
453
- /// _Godot equivalent: Projection.jitter_offseted()_
435
+ /// _Godot equivalent: ` Projection.jitter_offseted()` _
454
436
#[ must_use]
455
437
pub fn jitter_offset ( & self , offset : Vector2 ) -> Self {
456
438
Self :: from_cols (
@@ -466,7 +448,7 @@ impl Projection {
466
448
///
467
449
/// Note: The original Projection must be a perspective projection.
468
450
///
469
- /// _Godot equivalent: Projection.perspective_znear_adjusted()_
451
+ /// _Godot equivalent: ` Projection.perspective_znear_adjusted()` _
470
452
pub fn perspective_znear_adjusted ( & self , new_znear : real ) -> Self {
471
453
self . as_inner ( )
472
454
. perspective_znear_adjusted ( new_znear. as_f64 ( ) )
@@ -545,8 +527,7 @@ impl GlamConv for Projection {
545
527
type Glam = RMat4 ;
546
528
}
547
529
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.
550
531
unsafe impl GodotFfi for Projection {
551
532
fn variant_type ( ) -> sys:: VariantType {
552
533
sys:: VariantType :: Projection
@@ -557,7 +538,9 @@ unsafe impl GodotFfi for Projection {
557
538
558
539
impl_godot_as_self ! ( Projection ) ;
559
540
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).
561
544
#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
562
545
#[ repr( C ) ]
563
546
pub enum ProjectionPlane {
@@ -569,33 +552,60 @@ pub enum ProjectionPlane {
569
552
Bottom = 5 ,
570
553
}
571
554
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.
574
571
#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
575
572
#[ repr( C ) ]
576
573
pub enum ProjectionEye {
577
574
Left = 1 ,
578
575
Right = 2 ,
579
576
}
580
577
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
+
581
589
impl std:: fmt:: Display for Projection {
582
590
/// Formats `Projection` to match Godot's string representation.
583
591
///
584
592
/// # Example
585
593
/// ```
586
- /// use godot::prelude::*;
594
+ /// # use godot::prelude::*;
587
595
/// let proj = Projection::new([
588
596
/// Vector4::new(1.0, 2.5, 1.0, 0.5),
589
597
/// Vector4::new(0.0, 1.5, 2.0, 0.5),
590
598
/// Vector4::new(0.0, 0.0, 3.0, 2.5),
591
599
/// Vector4::new(3.0, 1.0, 4.0, 1.5),
592
600
/// ]);
601
+ ///
593
602
/// const FMT_RESULT: &str = r"
594
603
/// 1, 0, 0, 3
595
604
/// 2.5, 1.5, 0, 1
596
605
/// 1, 2, 3, 4
597
606
/// 0.5, 0.5, 2.5, 1.5
598
607
/// ";
608
+ ///
599
609
/// assert_eq!(format!("{}", proj), FMT_RESULT);
600
610
/// ```
601
611
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
0 commit comments