From 040ac676513ed269e7ef0485bb11f4761526c7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 01:58:24 +0200 Subject: [PATCH 1/6] Update traits --- crates/bevy_gizmos/src/primitives/dim3.rs | 265 ++++++++++++---------- 1 file changed, 142 insertions(+), 123 deletions(-) diff --git a/crates/bevy_gizmos/src/primitives/dim3.rs b/crates/bevy_gizmos/src/primitives/dim3.rs index 898850ddea901..990cd3121c8cd 100644 --- a/crates/bevy_gizmos/src/primitives/dim3.rs +++ b/crates/bevy_gizmos/src/primitives/dim3.rs @@ -18,24 +18,43 @@ const DEFAULT_RESOLUTION: u32 = 5; const INFINITE_LEN: f32 = 10_000.0; /// A trait for rendering 3D geometric primitives (`P`) with [`GizmoBuffer`]. -pub trait GizmoPrimitive3d { +pub trait GizmoPrimitive3d : Primitive3d +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync +{ /// The output of `primitive_3d`. This is a builder to set non-default values. type Output<'a> where Self: 'a; /// Renders a 3D primitive with its associated details. - fn primitive_3d( - &mut self, - primitive: &P, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, + isometry: impl Into, + color: impl Into, + ) -> Self::Output<'a>; +} +impl GizmoBuffer +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + /// Renders a 3D primitive with its associated details. + pub fn primitive_3d<'a, 'b: 'a, P: GizmoPrimitive3d>( + &'b mut self, + primitive: &'a P, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_>; + ) -> P::Output<'a> { + primitive.gizmos(self, isometry, color) + } } // direction 3d -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Dir3 where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -45,22 +64,22 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Dir3, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { let isometry = isometry.into(); let start = Vec3::ZERO; - let end = primitive.as_vec3(); - self.arrow(isometry * start, isometry * end, color); + let end = self.as_vec3(); + gizmos.arrow(isometry * start, isometry * end, color); } } // sphere -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Sphere where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -70,13 +89,13 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Sphere, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - self.sphere(isometry, primitive.radius, color) + ) -> Self::Output<'a> { + gizmos.sphere(isometry, self.radius, color) } } @@ -121,7 +140,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Plane3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -131,15 +150,15 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Plane3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { Plane3dBuilder { - gizmos: self, - normal: primitive.normal, + gizmos, + normal: self.normal, isometry: isometry.into(), color: color.into(), cell_count: UVec2::splat(3), @@ -173,7 +192,7 @@ where // line 3d -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Line3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -183,32 +202,32 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Line3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } let isometry = isometry.into(); let color = color.into(); - let direction = primitive.direction.as_vec3(); - self.arrow(isometry * Vec3::ZERO, isometry * direction, color); + let direction = self.direction.as_vec3(); + gizmos.arrow(isometry * Vec3::ZERO, isometry * direction, color); let [start, end] = [1.0, -1.0] .map(|sign| sign * INFINITE_LEN) - .map(|length| primitive.direction * length) + .map(|length| self.direction * length) .map(|offset| isometry * offset); - self.line(start, end, color); + gizmos.line(start, end, color); } } // segment 3d -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Segment3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -218,24 +237,24 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Segment3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } - let transformed = primitive.transformed(isometry); - self.line(transformed.point1(), transformed.point2(), color); + let transformed = self.transformed(isometry); + gizmos.line(transformed.point1(), transformed.point2(), color); } } // polyline 3d -impl GizmoPrimitive3d> for GizmoBuffer +impl GizmoPrimitive3d for Polyline3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -245,24 +264,24 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Polyline3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } let isometry = isometry.into(); - self.linestrip(primitive.vertices.map(|vec3| isometry * vec3), color); + gizmos.linestrip(self.vertices.map(|vec3| isometry * vec3), color); } } // boxed polyline 3d -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for BoxedPolyline3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -272,19 +291,19 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &BoxedPolyline3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } let isometry = isometry.into(); - self.linestrip( - primitive + gizmos.linestrip( + self .vertices .iter() .copied() @@ -296,7 +315,7 @@ where // triangle 3d -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Triangle3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -306,25 +325,25 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Triangle3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } let isometry = isometry.into(); - let [a, b, c] = primitive.vertices; - self.linestrip([a, b, c, a].map(|vec3| isometry * vec3), color); + let [a, b, c] = self.vertices; + gizmos.linestrip([a, b, c, a].map(|vec3| isometry * vec3), color); } } // cuboid -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Cuboid where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -334,13 +353,13 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Cuboid, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } @@ -358,7 +377,7 @@ where [1.0, -1.0, -1.0], ] .map(Vec3::from) - .map(|vec3| vec3 * primitive.half_size) + .map(|vec3| vec3 * self.half_size) .map(|vec3| isometry * vec3); // lines for the upper rectangle of the cuboid @@ -379,7 +398,7 @@ where .chain(lower) .chain(connections) .for_each(|(start, end)| { - self.line(start, end, color); + gizmos.line(start, end, color); }); } } @@ -419,7 +438,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Cylinder where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -429,16 +448,16 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Cylinder, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { Cylinder3dBuilder { - gizmos: self, - radius: primitive.radius, - half_height: primitive.half_height, + gizmos, + radius: self.radius, + half_height: self.half_height, isometry: isometry.into(), color: color.into(), resolution: DEFAULT_RESOLUTION, @@ -505,7 +524,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Capsule3d where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -515,16 +534,16 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Capsule3d, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { Capsule3dBuilder { - gizmos: self, - radius: primitive.radius, - half_length: primitive.half_length, + gizmos, + radius: self.radius, + half_length: self.half_length, isometry: isometry.into(), color: color.into(), resolution: DEFAULT_RESOLUTION, @@ -645,7 +664,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Cone where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -655,16 +674,16 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Cone, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { Cone3dBuilder { - gizmos: self, - radius: primitive.radius, - height: primitive.height, + gizmos, + radius: self.radius, + height: self.height, isometry: isometry.into(), color: color.into(), base_resolution: DEFAULT_RESOLUTION, @@ -747,7 +766,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for ConicalFrustum where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -757,17 +776,17 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &ConicalFrustum, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { ConicalFrustum3dBuilder { - gizmos: self, - radius_top: primitive.radius_top, - radius_bottom: primitive.radius_bottom, - height: primitive.height, + gizmos, + radius_top: self.radius_top, + radius_bottom: self.radius_bottom, + height: self.height, isometry: isometry.into(), color: color.into(), resolution: DEFAULT_RESOLUTION, @@ -851,7 +870,7 @@ where } } -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Torus where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -861,16 +880,16 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Torus, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { + ) -> Self::Output<'a> { Torus3dBuilder { - gizmos: self, - minor_radius: primitive.minor_radius, - major_radius: primitive.major_radius, + gizmos, + minor_radius: self.minor_radius, + major_radius: self.major_radius, isometry: isometry.into(), color: color.into(), minor_resolution: DEFAULT_RESOLUTION, @@ -931,7 +950,7 @@ where // tetrahedron -impl GizmoPrimitive3d for GizmoBuffer +impl GizmoPrimitive3d for Tetrahedron where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -941,25 +960,25 @@ where where Self: 'a; - fn primitive_3d( - &mut self, - primitive: &Tetrahedron, + fn gizmos<'a, 'b: 'a>( + &'a self, + gizmos: &'b mut GizmoBuffer, isometry: impl Into, color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { + ) -> Self::Output<'a> { + if !gizmos.enabled { return; } let isometry = isometry.into(); - let [a, b, c, d] = primitive.vertices.map(|vec3| isometry * vec3); + let [a, b, c, d] = self.vertices.map(|vec3| isometry * vec3); let lines = [(a, b), (a, c), (a, d), (b, c), (b, d), (c, d)]; let color = color.into(); lines.into_iter().for_each(|(start, end)| { - self.line(start, end, color); + gizmos.line(start, end, color); }); } } From eaa38a897195cc6221a7be85479e726e5e2a998c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:03:54 +0200 Subject: [PATCH 2/6] Add more documentation --- crates/bevy_gizmos/src/primitives/dim3.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/bevy_gizmos/src/primitives/dim3.rs b/crates/bevy_gizmos/src/primitives/dim3.rs index 990cd3121c8cd..dbd641b147e5b 100644 --- a/crates/bevy_gizmos/src/primitives/dim3.rs +++ b/crates/bevy_gizmos/src/primitives/dim3.rs @@ -18,17 +18,24 @@ const DEFAULT_RESOLUTION: u32 = 5; const INFINITE_LEN: f32 = 10_000.0; /// A trait for rendering 3D geometric primitives (`P`) with [`GizmoBuffer`]. -pub trait GizmoPrimitive3d : Primitive3d +/// +/// This trait is used internally when calling [`gizmos.primitive_3d`]. +/// +/// If you want to implement gizmos support for a custom primitive you should +/// implement this trait. +pub trait GizmoPrimitive3d: Primitive3d where Config: GizmoConfigGroup, - Clear: 'static + Send + Sync + Clear: 'static + Send + Sync, { - /// The output of `primitive_3d`. This is a builder to set non-default values. + /// The output of `gizmos.primitive_3d` and `self.gizmos`. This is a builder to set non-default values. type Output<'a> where Self: 'a; /// Renders a 3D primitive with its associated details. + /// + /// This is identical to `gizmos.primitive_3d`. fn gizmos<'a, 'b: 'a>( &'a self, gizmos: &'b mut GizmoBuffer, @@ -303,11 +310,7 @@ where let isometry = isometry.into(); gizmos.linestrip( - self - .vertices - .iter() - .copied() - .map(|vec3| isometry * vec3), + self.vertices.iter().copied().map(|vec3| isometry * vec3), color, ); } From dbd7999c02f8f5f22fd526ef41cc1d93e9d7aa6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 02:21:41 +0200 Subject: [PATCH 3/6] Remove unused import --- crates/bevy_gizmos/src/light.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/bevy_gizmos/src/light.rs b/crates/bevy_gizmos/src/light.rs index 1bd6ee3cacb05..796ed2ddfa903 100644 --- a/crates/bevy_gizmos/src/light.rs +++ b/crates/bevy_gizmos/src/light.rs @@ -2,8 +2,6 @@ use core::f32::consts::PI; -use crate::primitives::dim3::GizmoPrimitive3d; - use bevy_app::{Plugin, PostUpdate}; use bevy_color::{ palettes::basic::{BLUE, GREEN, RED}, From ff08a5ef07471d6258e8e41fc751e6cd6f7de24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 18:56:15 +0200 Subject: [PATCH 4/6] Add release notes --- .../migration-guides/extendable_gizmos_primitives.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 release-content/migration-guides/extendable_gizmos_primitives.md diff --git a/release-content/migration-guides/extendable_gizmos_primitives.md b/release-content/migration-guides/extendable_gizmos_primitives.md new file mode 100644 index 0000000000000..d318f7fa63095 --- /dev/null +++ b/release-content/migration-guides/extendable_gizmos_primitives.md @@ -0,0 +1,10 @@ +--- +title: Extendable Gizmo-Primitives +authors: ["@lynn-lumen"] +pull_requests: [20049] +--- + +The `GizmoPrimitive3d` trait, which is used to draw primitives using gizmos can now be implemented for custom primitives. +If you did not declare any such primitives, you may need to remove this trait as it will now be unused. + +If you did implement `GizmoPrimitive3d` for a custom `GizmoBuffer`-like struct, you will need to move your implementation for custom primitives to the primitive itself and use that implementation in a seperate method on the previously mentioned struct. \ No newline at end of file From adb06ed8b900239759c2427d62c40b17ada65e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 18:58:26 +0200 Subject: [PATCH 5/6] Fix typo --- .../migration-guides/extendable_gizmos_primitives.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/migration-guides/extendable_gizmos_primitives.md b/release-content/migration-guides/extendable_gizmos_primitives.md index d318f7fa63095..92950e5266662 100644 --- a/release-content/migration-guides/extendable_gizmos_primitives.md +++ b/release-content/migration-guides/extendable_gizmos_primitives.md @@ -7,4 +7,4 @@ pull_requests: [20049] The `GizmoPrimitive3d` trait, which is used to draw primitives using gizmos can now be implemented for custom primitives. If you did not declare any such primitives, you may need to remove this trait as it will now be unused. -If you did implement `GizmoPrimitive3d` for a custom `GizmoBuffer`-like struct, you will need to move your implementation for custom primitives to the primitive itself and use that implementation in a seperate method on the previously mentioned struct. \ No newline at end of file +If you did implement `GizmoPrimitive3d` for a custom `GizmoBuffer`-like struct, you will need to move your implementation for custom primitives to the primitive itself and use that implementation in a separate method on the previously mentioned struct. \ No newline at end of file From 966aafd1999a1ef4b47ad33d1bb5b0a9b131e2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lynn=20B=C3=BCttgenbach?= <62256001+lynn-lumen@users.noreply.github.com> Date: Wed, 9 Jul 2025 19:05:24 +0200 Subject: [PATCH 6/6] Add single new line --- .../migration-guides/extendable_gizmos_primitives.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/release-content/migration-guides/extendable_gizmos_primitives.md b/release-content/migration-guides/extendable_gizmos_primitives.md index 92950e5266662..6dc5e46c1f8f3 100644 --- a/release-content/migration-guides/extendable_gizmos_primitives.md +++ b/release-content/migration-guides/extendable_gizmos_primitives.md @@ -4,7 +4,7 @@ authors: ["@lynn-lumen"] pull_requests: [20049] --- -The `GizmoPrimitive3d` trait, which is used to draw primitives using gizmos can now be implemented for custom primitives. -If you did not declare any such primitives, you may need to remove this trait as it will now be unused. +The `GizmoPrimitive3d` trait, which is used to draw primitives using gizmos can now be implemented for custom primitives. +If you did not declare any such primitives, you may need to remove this trait as it will now be unused. -If you did implement `GizmoPrimitive3d` for a custom `GizmoBuffer`-like struct, you will need to move your implementation for custom primitives to the primitive itself and use that implementation in a separate method on the previously mentioned struct. \ No newline at end of file +If you did implement `GizmoPrimitive3d` for a custom `GizmoBuffer`-like struct, you will need to move your implementation for custom primitives to the primitive itself and use that implementation in a separate method on the previously mentioned struct.