From b1ab0363290c27af5e20007b202f608d43855193 Mon Sep 17 00:00:00 2001 From: Aceeri Date: Mon, 22 Apr 2024 17:16:12 -0700 Subject: [PATCH] Contextually clearing gizmos (#10973) # Objective Allow `Gizmos` to work in `FixedUpdate` without any changes needed. This changes `Gizmos` from being a purely immediate mode api, but allows the user to use it as if it were an immediate mode API regardless of schedule context. Also allows for extending by other custom schedules by adding their own `GizmoStorage` and the requisite systems: - `propagate_gizmos::` before `update_gizmo_meshes` - `stash_default_gizmos` when starting a clear context - `pop_default_gizmos` when ending a clear context - `collect_default_gizmos` when grabbing the requested gizmos - `clear_gizmos` for clearing the context's gizmos ## Solution Adds a generic to `Gizmos` that defaults to `Update` (the current way gizmos works). When entering a new clear context the default `Gizmos` gets swapped out for that context's duration so the context can collect the gizmos requested. Prior work: https://github.com/bevyengine/bevy/pull/9153 ## To do - [x] `FixedUpdate` should probably get its own First, Pre, Update, Post, Last system sets for this. Otherwise users will need to make sure to order their systems before `clear_gizmos`. This could alternatively be fixed by moving the setup of this to `bevy_time::fixed`? PR to fix this issue: https://github.com/bevyengine/bevy/pull/10977 - [x] use mem::take internally for the swaps? - [x] Better name for the `Context` generic on gizmos? `Clear`? --- ## Changelog - Gizmos drawn in `FixedMain` now last until the next `FixedMain` iteration runs. --- crates/bevy_gizmos/Cargo.toml | 1 + crates/bevy_gizmos/src/arcs.rs | 62 +++-- crates/bevy_gizmos/src/arrows.rs | 36 ++- crates/bevy_gizmos/src/circles.rs | 55 +++-- crates/bevy_gizmos/src/gizmos.rs | 227 +++++++++++++++--- crates/bevy_gizmos/src/grid.rs | 64 +++-- crates/bevy_gizmos/src/lib.rs | 161 +++++++++---- crates/bevy_gizmos/src/primitives/dim2.rs | 130 ++++++++--- crates/bevy_gizmos/src/primitives/dim3.rs | 233 +++++++++++++++---- crates/bevy_gizmos/src/primitives/helpers.rs | 27 ++- 10 files changed, 787 insertions(+), 209 deletions(-) diff --git a/crates/bevy_gizmos/Cargo.toml b/crates/bevy_gizmos/Cargo.toml index 039151b1612c7..74d12da3a95a5 100644 --- a/crates/bevy_gizmos/Cargo.toml +++ b/crates/bevy_gizmos/Cargo.toml @@ -27,6 +27,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.14.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.14.0-dev" } bevy_gizmos_macros = { path = "macros", version = "0.14.0-dev" } +bevy_time = { path = "../bevy_time", version = "0.14.0-dev" } bytemuck = "1.0" diff --git a/crates/bevy_gizmos/src/arcs.rs b/crates/bevy_gizmos/src/arcs.rs index 39a06d5ff5208..f94ed26d42307 100644 --- a/crates/bevy_gizmos/src/arcs.rs +++ b/crates/bevy_gizmos/src/arcs.rs @@ -11,7 +11,11 @@ use std::f32::consts::TAU; // === 2D === -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw an arc, which is a part of the circumference of a circle, in 2D. /// /// This should be called for each frame the arc needs to be rendered. @@ -50,7 +54,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { arc_angle: f32, radius: f32, color: impl Into, - ) -> Arc2dBuilder<'_, 'w, 's, T> { + ) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> { Arc2dBuilder { gizmos: self, position, @@ -64,8 +68,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } /// A builder returned by [`Gizmos::arc_2d`]. -pub struct Arc2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Arc2dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec2, direction_angle: f32, arc_angle: f32, @@ -74,7 +82,11 @@ pub struct Arc2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: Option, } -impl Arc2dBuilder<'_, '_, '_, T> { +impl Arc2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of line-segments for this arc. pub fn segments(mut self, segments: usize) -> Self { self.segments.replace(segments); @@ -82,7 +94,11 @@ impl Arc2dBuilder<'_, '_, '_, T> { } } -impl Drop for Arc2dBuilder<'_, '_, '_, T> { +impl Drop for Arc2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -114,7 +130,11 @@ fn arc_2d_inner( // === 3D === -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw an arc, which is a part of the circumference of a circle, in 3D. For default values /// this is drawing a standard arc. A standard arc is defined as /// @@ -169,7 +189,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { position: Vec3, rotation: Quat, color: impl Into, - ) -> Arc3dBuilder<'_, 'w, 's, T> { + ) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> { Arc3dBuilder { gizmos: self, start_vertex: Vec3::X, @@ -226,7 +246,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { from: Vec3, to: Vec3, color: impl Into, - ) -> Arc3dBuilder<'_, 'w, 's, T> { + ) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> { self.arc_from_to(center, from, to, color, |x| x) } @@ -273,7 +293,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { from: Vec3, to: Vec3, color: impl Into, - ) -> Arc3dBuilder<'_, 'w, 's, T> { + ) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> { self.arc_from_to(center, from, to, color, |angle| { if angle > 0.0 { TAU - angle @@ -293,7 +313,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { to: Vec3, color: impl Into, angle_fn: impl Fn(f32) -> f32, - ) -> Arc3dBuilder<'_, 'w, 's, T> { + ) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> { // `from` and `to` can be the same here since in either case nothing gets rendered and the // orientation ambiguity of `up` doesn't matter let from_axis = (from - center).normalize_or_zero(); @@ -320,8 +340,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } /// A builder returned by [`Gizmos::arc_2d`]. -pub struct Arc3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Arc3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // this is the vertex the arc starts on in the XZ plane. For the normal arc_3d method this is // always starting at Vec3::X. For the short/long arc methods we actually need a way to start // at the from position and this is where this internal field comes into play. Some implicit @@ -340,7 +364,11 @@ pub struct Arc3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: Option, } -impl Arc3dBuilder<'_, '_, '_, T> { +impl Arc3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of line-segments for this arc. pub fn segments(mut self, segments: usize) -> Self { self.segments.replace(segments); @@ -348,7 +376,11 @@ impl Arc3dBuilder<'_, '_, '_, T> { } } -impl Drop for Arc3dBuilder<'_, '_, '_, T> { +impl Drop for Arc3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; diff --git a/crates/bevy_gizmos/src/arrows.rs b/crates/bevy_gizmos/src/arrows.rs index dd333da129403..339df992e2f8e 100644 --- a/crates/bevy_gizmos/src/arrows.rs +++ b/crates/bevy_gizmos/src/arrows.rs @@ -12,8 +12,12 @@ use bevy_math::{Quat, Vec2, Vec3}; use bevy_transform::TransformPoint; /// A builder returned by [`Gizmos::arrow`] and [`Gizmos::arrow_2d`] -pub struct ArrowBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct ArrowBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, start: Vec3, end: Vec3, color: Color, @@ -21,7 +25,11 @@ pub struct ArrowBuilder<'a, 'w, 's, T: GizmoConfigGroup> { tip_length: f32, } -impl ArrowBuilder<'_, '_, '_, T> { +impl ArrowBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Change the length of the tips to be `length`. /// The default tip length is [length of the arrow]/10. /// @@ -51,7 +59,11 @@ impl ArrowBuilder<'_, '_, '_, T> { } } -impl Drop for ArrowBuilder<'_, '_, '_, T> { +impl Drop for ArrowBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draws the arrow, by drawing lines with the stored [`Gizmos`] fn drop(&mut self) { if !self.gizmos.enabled { @@ -90,7 +102,11 @@ impl Drop for ArrowBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw an arrow in 3D, from `start` to `end`. Has four tips for convenient viewing from any direction. /// /// This should be called for each frame the arrow needs to be rendered. @@ -111,7 +127,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { start: Vec3, end: Vec3, color: impl Into, - ) -> ArrowBuilder<'_, 'w, 's, T> { + ) -> ArrowBuilder<'_, 'w, 's, Config, Clear> { let length = (end - start).length(); ArrowBuilder { gizmos: self, @@ -143,12 +159,16 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { start: Vec2, end: Vec2, color: impl Into, - ) -> ArrowBuilder<'_, 'w, 's, T> { + ) -> ArrowBuilder<'_, 'w, 's, Config, Clear> { self.arrow(start.extend(0.), end.extend(0.), color) } } -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw a set of axes local to the given transform (`transform`), with length scaled by a factor /// of `base_length`. /// diff --git a/crates/bevy_gizmos/src/circles.rs b/crates/bevy_gizmos/src/circles.rs index af22d095274cf..af94ad9374b67 100644 --- a/crates/bevy_gizmos/src/circles.rs +++ b/crates/bevy_gizmos/src/circles.rs @@ -19,7 +19,11 @@ fn ellipse_inner(half_size: Vec2, segments: usize) -> impl Iterator }) } -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw an ellipse in 3D at `position` with the flat side facing `normal`. /// /// This should be called for each frame the ellipse needs to be rendered. @@ -48,7 +52,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { rotation: Quat, half_size: Vec2, color: impl Into, - ) -> EllipseBuilder<'_, 'w, 's, T> { + ) -> EllipseBuilder<'_, 'w, 's, Config, Clear> { EllipseBuilder { gizmos: self, position, @@ -87,7 +91,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { angle: f32, half_size: Vec2, color: impl Into, - ) -> Ellipse2dBuilder<'_, 'w, 's, T> { + ) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> { Ellipse2dBuilder { gizmos: self, position, @@ -126,7 +130,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { normal: Dir3, radius: f32, color: impl Into, - ) -> EllipseBuilder<'_, 'w, 's, T> { + ) -> EllipseBuilder<'_, 'w, 's, Config, Clear> { EllipseBuilder { gizmos: self, position, @@ -164,7 +168,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { position: Vec2, radius: f32, color: impl Into, - ) -> Ellipse2dBuilder<'_, 'w, 's, T> { + ) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> { Ellipse2dBuilder { gizmos: self, position, @@ -177,8 +181,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } /// A builder returned by [`Gizmos::ellipse`]. -pub struct EllipseBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct EllipseBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec3, rotation: Quat, half_size: Vec2, @@ -186,7 +194,11 @@ pub struct EllipseBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl EllipseBuilder<'_, '_, '_, T> { +impl EllipseBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of line-segments for this ellipse. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -194,7 +206,11 @@ impl EllipseBuilder<'_, '_, '_, T> { } } -impl Drop for EllipseBuilder<'_, '_, '_, T> { +impl Drop for EllipseBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -208,8 +224,12 @@ impl Drop for EllipseBuilder<'_, '_, '_, T> { } /// A builder returned by [`Gizmos::ellipse_2d`]. -pub struct Ellipse2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Ellipse2dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec2, rotation: Mat2, half_size: Vec2, @@ -217,7 +237,11 @@ pub struct Ellipse2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl Ellipse2dBuilder<'_, '_, '_, T> { +impl Ellipse2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of line-segments for this ellipse. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -225,7 +249,12 @@ impl Ellipse2dBuilder<'_, '_, '_, T> { } } -impl Drop for Ellipse2dBuilder<'_, '_, '_, T> { +impl Drop for Ellipse2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + /// Set the number of line-segments for this ellipse. fn drop(&mut self) { if !self.gizmos.enabled { return; diff --git a/crates/bevy_gizmos/src/gizmos.rs b/crates/bevy_gizmos/src/gizmos.rs index bf0cc8a9c236a..c62e8b25d891f 100644 --- a/crates/bevy_gizmos/src/gizmos.rs +++ b/crates/bevy_gizmos/src/gizmos.rs @@ -1,6 +1,6 @@ //! A module for the [`Gizmos`] [`SystemParam`]. -use std::{iter, marker::PhantomData}; +use std::{iter, marker::PhantomData, mem}; use crate::circles::DEFAULT_CIRCLE_SEGMENTS; use bevy_color::{Color, LinearRgba}; @@ -11,6 +11,7 @@ use bevy_ecs::{ }; use bevy_math::{Dir3, Quat, Rotation2d, Vec2, Vec3}; use bevy_transform::TransformPoint; +use bevy_utils::default; use crate::{ config::GizmoConfigGroup, @@ -18,47 +19,157 @@ use crate::{ prelude::GizmoConfig, }; -#[derive(Resource, Default)] -pub(crate) struct GizmoStorage { +/// Storage of gizmo primitives. +#[derive(Resource)] +pub struct GizmoStorage { pub(crate) list_positions: Vec, pub(crate) list_colors: Vec, pub(crate) strip_positions: Vec, pub(crate) strip_colors: Vec, - marker: PhantomData, + marker: PhantomData<(Config, Clear)>, } +impl Default for GizmoStorage { + fn default() -> Self { + Self { + list_positions: default(), + list_colors: default(), + strip_positions: default(), + strip_colors: default(), + marker: PhantomData, + } + } +} + +impl GizmoStorage +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + /// Combine the other gizmo storage with this one. + pub fn append_storage( + &mut self, + other: &GizmoStorage, + ) { + self.list_positions.extend(other.list_positions.iter()); + self.list_colors.extend(other.list_colors.iter()); + self.strip_positions.extend(other.strip_positions.iter()); + self.strip_colors.extend(other.strip_colors.iter()); + } + + pub(crate) fn swap( + &mut self, + other: &mut GizmoStorage, + ) { + mem::swap(&mut self.list_positions, &mut other.list_positions); + mem::swap(&mut self.list_colors, &mut other.list_colors); + mem::swap(&mut self.strip_positions, &mut other.strip_positions); + mem::swap(&mut self.strip_colors, &mut other.strip_colors); + } + + /// Clear this gizmo storage of any requested gizmos. + pub fn clear(&mut self) { + self.list_positions.clear(); + self.list_colors.clear(); + self.strip_positions.clear(); + self.strip_colors.clear(); + } +} + +/// Swap buffer for a specific clearing context. +/// +/// This is to stash/store the default/requested gizmos so another context can +/// be substituted for that duration. +pub struct Swap(PhantomData); + /// A [`SystemParam`] for drawing gizmos. /// /// They are drawn in immediate mode, which means they will be rendered only for -/// the frames in which they are spawned. -/// Gizmos should be spawned before the [`Last`](bevy_app::Last) schedule to ensure they are drawn. -pub struct Gizmos<'w, 's, T: GizmoConfigGroup = DefaultGizmoConfigGroup> { - buffer: Deferred<'s, GizmoBuffer>, +/// the frames, or ticks when in [`FixedMain`](bevy_app::FixedMain), in which +/// they are spawned. +/// +/// A system in [`Main`](bevy_app::Main) will be cleared each rendering +/// frame, while a system in [`FixedMain`](bevy_app::FixedMain) will be +/// cleared each time the [`RunFixedMainLoop`](bevy_app::RunFixedMainLoop) +/// schedule is run. +/// +/// Gizmos should be spawned before the [`Last`](bevy_app::Last) schedule +/// to ensure they are drawn. +/// +/// To set up your own clearing context (useful for custom scheduling similar +/// to [`FixedMain`](bevy_app::FixedMain)): +/// +/// ``` +/// use bevy_gizmos::{prelude::*, *, gizmos::GizmoStorage}; +/// # use bevy_app::prelude::*; +/// # use bevy_ecs::{schedule::ScheduleLabel, prelude::*}; +/// # #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +/// # struct StartOfMyContext; +/// # #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +/// # struct EndOfMyContext; +/// # #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +/// # struct StartOfRun; +/// # #[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)] +/// # struct EndOfRun; +/// # struct MyContext; +/// struct ClearContextSetup; +/// impl Plugin for ClearContextSetup { +/// fn build(&self, app: &mut App) { +/// app.init_resource::>() +/// // Make sure this context starts/ends cleanly if inside another context. E.g. it +/// // should start after the parent context starts and end after the parent context ends. +/// .add_systems(StartOfMyContext, start_gizmo_context::) +/// // If not running multiple times, put this with [`start_gizmo_context`]. +/// .add_systems(StartOfRun, clear_gizmo_context::) +/// // If not running multiple times, put this with [`end_gizmo_context`]. +/// .add_systems(EndOfRun, collect_requested_gizmos::) +/// .add_systems(EndOfMyContext, end_gizmo_context::) +/// .add_systems( +/// Last, +/// propagate_gizmos::.before(UpdateGizmoMeshes), +/// ); +/// } +/// } +/// ``` +pub struct Gizmos<'w, 's, Config = DefaultGizmoConfigGroup, Clear = ()> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + buffer: Deferred<'s, GizmoBuffer>, pub(crate) enabled: bool, /// The currently used [`GizmoConfig`] pub config: &'w GizmoConfig, /// The currently used [`GizmoConfigGroup`] - pub config_ext: &'w T, + pub config_ext: &'w Config, } -type GizmosState = ( - Deferred<'static, GizmoBuffer>, +type GizmosState = ( + Deferred<'static, GizmoBuffer>, Res<'static, GizmoConfigStore>, ); #[doc(hidden)] -pub struct GizmosFetchState { - state: as SystemParam>::State, +pub struct GizmosFetchState +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + state: as SystemParam>::State, } #[allow(unsafe_code)] // SAFETY: All methods are delegated to existing `SystemParam` implementations -unsafe impl SystemParam for Gizmos<'_, '_, T> { - type State = GizmosFetchState; - type Item<'w, 's> = Gizmos<'w, 's, T>; +unsafe impl SystemParam for Gizmos<'_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type State = GizmosFetchState; + type Item<'w, 's> = Gizmos<'w, 's, Config, Clear>; fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State { GizmosFetchState { - state: GizmosState::::init_state(world, system_meta), + state: GizmosState::::init_state(world, system_meta), } } @@ -68,11 +179,13 @@ unsafe impl SystemParam for Gizmos<'_, '_, T> { system_meta: &mut SystemMeta, ) { // SAFETY: The caller ensures that `archetype` is from the World the state was initialized from in `init_state`. - unsafe { GizmosState::::new_archetype(&mut state.state, archetype, system_meta) }; + unsafe { + GizmosState::::new_archetype(&mut state.state, archetype, system_meta); + }; } fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) { - GizmosState::::apply(&mut state.state, system_meta, world); + GizmosState::::apply(&mut state.state, system_meta, world); } unsafe fn get_param<'w, 's>( @@ -83,12 +196,17 @@ unsafe impl SystemParam for Gizmos<'_, '_, T> { ) -> Self::Item<'w, 's> { // SAFETY: Delegated to existing `SystemParam` implementations let (f0, f1) = unsafe { - GizmosState::::get_param(&mut state.state, system_meta, world, change_tick) + GizmosState::::get_param( + &mut state.state, + system_meta, + world, + change_tick, + ) }; // Accessing the GizmoConfigStore in the immediate mode API reduces performance significantly. // Implementing SystemParam manually allows us to do it to here // Having config available allows for early returns when gizmos are disabled - let (config, config_ext) = f1.into_inner().config::(); + let (config, config_ext) = f1.into_inner().config::(); Gizmos { buffer: f0, enabled: config.enabled, @@ -100,25 +218,50 @@ unsafe impl SystemParam for Gizmos<'_, '_, T> { #[allow(unsafe_code)] // Safety: Each field is `ReadOnlySystemParam`, and Gizmos SystemParam does not mutate world -unsafe impl<'w, 's, T: GizmoConfigGroup> ReadOnlySystemParam for Gizmos<'w, 's, T> +unsafe impl<'w, 's, Config, Clear> ReadOnlySystemParam for Gizmos<'w, 's, Config, Clear> where - Deferred<'s, GizmoBuffer>: ReadOnlySystemParam, + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, + Deferred<'s, GizmoBuffer>: ReadOnlySystemParam, Res<'w, GizmoConfigStore>: ReadOnlySystemParam, { } -#[derive(Default)] -struct GizmoBuffer { +struct GizmoBuffer +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ list_positions: Vec, list_colors: Vec, strip_positions: Vec, strip_colors: Vec, - marker: PhantomData, + marker: PhantomData<(Config, Clear)>, +} + +impl Default for GizmoBuffer +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + fn default() -> Self { + Self { + list_positions: default(), + list_colors: default(), + strip_positions: default(), + strip_colors: default(), + marker: PhantomData, + } + } } -impl SystemBuffer for GizmoBuffer { +impl SystemBuffer for GizmoBuffer +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn apply(&mut self, _system_meta: &SystemMeta, world: &mut World) { - let mut storage = world.resource_mut::>(); + let mut storage = world.resource_mut::>(); storage.list_positions.append(&mut self.list_positions); storage.list_colors.append(&mut self.list_colors); storage.strip_positions.append(&mut self.strip_positions); @@ -126,7 +269,11 @@ impl SystemBuffer for GizmoBuffer { } } -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw a line in 3D from `start` to `end`. /// /// This should be called for each frame the line needs to be rendered. @@ -340,7 +487,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { rotation: Quat, radius: f32, color: impl Into, - ) -> SphereBuilder<'_, 'w, 's, T> { + ) -> SphereBuilder<'_, 'w, 's, Config, Clear> { SphereBuilder { gizmos: self, position, @@ -644,8 +791,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } /// A builder returned by [`Gizmos::sphere`]. -pub struct SphereBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct SphereBuilder<'a, 'w, 's, Config, Clear = ()> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec3, rotation: Quat, radius: f32, @@ -653,7 +804,11 @@ pub struct SphereBuilder<'a, 'w, 's, T: GizmoConfigGroup> { circle_segments: usize, } -impl SphereBuilder<'_, '_, '_, T> { +impl SphereBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of line-segments per circle for this sphere. pub fn circle_segments(mut self, segments: usize) -> Self { self.circle_segments = segments; @@ -661,7 +816,11 @@ impl SphereBuilder<'_, '_, '_, T> { } } -impl Drop for SphereBuilder<'_, '_, '_, T> { +impl Drop for SphereBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; diff --git a/crates/bevy_gizmos/src/grid.rs b/crates/bevy_gizmos/src/grid.rs index a00a8c4fa19bc..7c7e3b5fa773b 100644 --- a/crates/bevy_gizmos/src/grid.rs +++ b/crates/bevy_gizmos/src/grid.rs @@ -8,8 +8,12 @@ use bevy_color::LinearRgba; use bevy_math::{Quat, UVec2, UVec3, Vec2, Vec3}; /// A builder returned by [`Gizmos::grid_3d`] -pub struct GridBuilder3d<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct GridBuilder3d<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec3, rotation: Quat, spacing: Vec3, @@ -19,8 +23,12 @@ pub struct GridBuilder3d<'a, 'w, 's, T: GizmoConfigGroup> { color: LinearRgba, } /// A builder returned by [`Gizmos::grid`] and [`Gizmos::grid_2d`] -pub struct GridBuilder2d<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct GridBuilder2d<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, position: Vec3, rotation: Quat, spacing: Vec2, @@ -30,7 +38,11 @@ pub struct GridBuilder2d<'a, 'w, 's, T: GizmoConfigGroup> { color: LinearRgba, } -impl GridBuilder3d<'_, '_, '_, T> { +impl GridBuilder3d<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Skews the grid by `tan(skew)` in the x direction. /// `skew` is in radians pub fn skew_x(mut self, skew: f32) -> Self { @@ -81,7 +93,12 @@ impl GridBuilder3d<'_, '_, '_, T> { self } } -impl GridBuilder2d<'_, '_, '_, T> { + +impl GridBuilder2d<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Skews the grid by `tan(skew)` in the x direction. /// `skew` is in radians pub fn skew_x(mut self, skew: f32) -> Self { @@ -121,7 +138,12 @@ impl GridBuilder2d<'_, '_, '_, T> { } } -impl Drop for GridBuilder3d<'_, '_, '_, T> { +impl Drop for GridBuilder3d<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + /// Draws a grid, by drawing lines with the stored [`Gizmos`] fn drop(&mut self) { draw_grid( self.gizmos, @@ -135,7 +157,12 @@ impl Drop for GridBuilder3d<'_, '_, '_, T> { ); } } -impl Drop for GridBuilder2d<'_, '_, '_, T> { + +impl Drop for GridBuilder2d<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { draw_grid( self.gizmos, @@ -149,7 +176,11 @@ impl Drop for GridBuilder2d<'_, '_, '_, T> { ); } } -impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Draw a 2D grid in 3D. /// /// This should be called for each frame the grid needs to be rendered. @@ -193,7 +224,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { cell_count: UVec2, spacing: Vec2, color: impl Into, - ) -> GridBuilder2d<'_, 'w, 's, T> { + ) -> GridBuilder2d<'_, 'w, 's, Config, Clear> { GridBuilder2d { gizmos: self, position, @@ -249,7 +280,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { cell_count: UVec3, spacing: Vec3, color: impl Into, - ) -> GridBuilder3d<'_, 'w, 's, T> { + ) -> GridBuilder3d<'_, 'w, 's, Config, Clear> { GridBuilder3d { gizmos: self, position, @@ -305,7 +336,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { cell_count: UVec2, spacing: Vec2, color: impl Into, - ) -> GridBuilder2d<'_, 'w, 's, T> { + ) -> GridBuilder2d<'_, 'w, 's, Config, Clear> { GridBuilder2d { gizmos: self, position: position.extend(0.), @@ -320,8 +351,8 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } #[allow(clippy::too_many_arguments)] -fn draw_grid( - gizmos: &mut Gizmos<'_, '_, T>, +fn draw_grid( + gizmos: &mut Gizmos<'_, '_, Config, Clear>, position: Vec3, rotation: Quat, spacing: Vec3, @@ -329,7 +360,10 @@ fn draw_grid( skew: Vec3, outer_edges: [bool; 3], color: LinearRgba, -) { +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ if !gizmos.enabled { return; } diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 06f9d762d8b6a..d523f0dd5403f 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -67,7 +67,7 @@ pub mod prelude { } use aabb::AabbGizmoPlugin; -use bevy_app::{App, Last, Plugin}; +use bevy_app::{App, FixedFirst, FixedLast, Last, Plugin, RunFixedMainLoop}; use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle}; use bevy_color::LinearRgba; use bevy_ecs::{ @@ -93,13 +93,14 @@ use bevy_render::{ renderer::RenderDevice, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; +use bevy_time::Fixed; use bevy_utils::TypeIdMap; use bytemuck::cast_slice; use config::{ DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoLineJoint, GizmoMeshConfig, }; -use gizmos::GizmoStorage; +use gizmos::{GizmoStorage, Swap}; #[cfg(feature = "bevy_pbr")] use light::LightGizmoPlugin; use std::{any::TypeId, mem}; @@ -186,67 +187,75 @@ impl Plugin for GizmoPlugin { } } -/// A trait adding `init_gizmo_group()` to the app +/// A extension trait adding `App::init_gizmo_group` and `App::insert_gizmo_config`. pub trait AppGizmoBuilder { - /// Registers [`GizmoConfigGroup`] `T` in the app enabling the use of [Gizmos<T>](crate::gizmos::Gizmos). + /// Registers [`GizmoConfigGroup`] in the app enabling the use of [Gizmos<Config>](crate::gizmos::Gizmos). /// /// Configurations can be set using the [`GizmoConfigStore`] [`Resource`]. - fn init_gizmo_group(&mut self) -> &mut Self; + fn init_gizmo_group(&mut self) -> &mut Self; - /// Insert the [`GizmoConfigGroup`] in the app with the given value and [`GizmoConfig`]. + /// Insert a [`GizmoConfig`] into a specific [`GizmoConfigGroup`]. /// /// This method should be preferred over [`AppGizmoBuilder::init_gizmo_group`] if and only if you need to configure fields upon initialization. - fn insert_gizmo_group( + fn insert_gizmo_config( &mut self, - group: T, + group: Config, config: GizmoConfig, ) -> &mut Self; } impl AppGizmoBuilder for App { - fn init_gizmo_group(&mut self) -> &mut Self { - if self.world().contains_resource::>() { + fn init_gizmo_group(&mut self) -> &mut Self { + if self.world().contains_resource::>() { return self; } + self.world_mut() + .get_resource_or_insert_with::(Default::default) + .register::(); + let mut handles = self .world_mut() .get_resource_or_insert_with::(Default::default); - handles.list.insert(TypeId::of::(), None); - handles.strip.insert(TypeId::of::(), None); - - self.init_resource::>() - .add_systems(Last, update_gizmo_meshes::); - self.world_mut() - .get_resource_or_insert_with::(Default::default) - .register::(); + handles.list.insert(TypeId::of::(), None); + handles.strip.insert(TypeId::of::(), None); + + self.init_resource::>() + .init_resource::>() + .init_resource::>>() + .add_systems( + RunFixedMainLoop, + start_gizmo_context::.before(bevy_time::run_fixed_main_schedule), + ) + .add_systems(FixedFirst, clear_gizmo_context::) + .add_systems(FixedLast, collect_requested_gizmos::) + .add_systems( + RunFixedMainLoop, + end_gizmo_context::.after(bevy_time::run_fixed_main_schedule), + ) + .add_systems( + Last, + ( + propagate_gizmos::.before(UpdateGizmoMeshes), + update_gizmo_meshes::.in_set(UpdateGizmoMeshes), + ), + ); self } - fn insert_gizmo_group( + fn insert_gizmo_config( &mut self, - group: T, + group: Config, config: GizmoConfig, ) -> &mut Self { + self.init_gizmo_group::(); + self.world_mut() .get_resource_or_insert_with::(Default::default) .insert(config, group); - if self.world().contains_resource::>() { - return self; - } - - let mut handles = self - .world_mut() - .get_resource_or_insert_with::(Default::default); - handles.list.insert(TypeId::of::(), None); - handles.strip.insert(TypeId::of::(), None); - - self.init_resource::>() - .add_systems(Last, update_gizmo_meshes::); - self } } @@ -262,15 +271,87 @@ struct LineGizmoHandles { strip: TypeIdMap>>, } -fn update_gizmo_meshes( +/// Start a new gizmo clearing context. +/// +/// Internally this pushes the parent default context into a swap buffer. +/// Gizmo contexts should be handled like a stack, so if you push a new context, +/// you must pop the context before the parent context ends. +pub fn start_gizmo_context( + mut swap: ResMut>>, + mut default: ResMut>, +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + default.swap(&mut *swap); +} + +/// End this gizmo clearing context. +/// +/// Pop the default gizmos context out of the [`Swap`] gizmo storage. +/// +/// This must be called before [`UpdateGizmoMeshes`] in the [`Last`] schedule. +pub fn end_gizmo_context( + mut swap: ResMut>>, + mut default: ResMut>, +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + default.clear(); + default.swap(&mut *swap); +} + +/// Collect the requested gizmos into a specific clear context. +pub fn collect_requested_gizmos( + mut update: ResMut>, + mut context: ResMut>, +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + context.append_storage(&update); + update.clear(); +} + +/// Clear out the contextual gizmos. +pub fn clear_gizmo_context(mut context: ResMut>) +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + context.clear(); +} + +/// Propagate the contextual gizmo into the `Update` storage for rendering. +/// +/// This should be before [`UpdateGizmoMeshes`]. +pub fn propagate_gizmos( + mut update_storage: ResMut>, + contextual_storage: Res>, +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + update_storage.append_storage(&*contextual_storage); +} + +/// System set for updating the rendering meshes for drawing gizmos. +#[derive(SystemSet, Clone, Debug, PartialEq, Eq, Hash)] +pub struct UpdateGizmoMeshes; + +/// Prepare gizmos for rendering. +/// +/// This also clears the default `GizmoStorage`. +fn update_gizmo_meshes( mut line_gizmos: ResMut>, mut handles: ResMut, - mut storage: ResMut>, + mut storage: ResMut>, config_store: Res, ) { if storage.list_positions.is_empty() { - handles.list.insert(TypeId::of::(), None); - } else if let Some(handle) = handles.list.get_mut(&TypeId::of::()) { + handles.list.insert(TypeId::of::(), None); + } else if let Some(handle) = handles.list.get_mut(&TypeId::of::()) { if let Some(handle) = handle { let list = line_gizmos.get_mut(handle.id()).unwrap(); @@ -289,10 +370,10 @@ fn update_gizmo_meshes( } } - let (config, _) = config_store.config::(); + let (config, _) = config_store.config::(); if storage.strip_positions.is_empty() { - handles.strip.insert(TypeId::of::(), None); - } else if let Some(handle) = handles.strip.get_mut(&TypeId::of::()) { + handles.strip.insert(TypeId::of::(), None); + } else if let Some(handle) = handles.strip.get_mut(&TypeId::of::()) { if let Some(handle) = handle { let strip = line_gizmos.get_mut(handle.id()).unwrap(); diff --git a/crates/bevy_gizmos/src/primitives/dim2.rs b/crates/bevy_gizmos/src/primitives/dim2.rs index dfc2813b5ee40..1162df7da9056 100644 --- a/crates/bevy_gizmos/src/primitives/dim2.rs +++ b/crates/bevy_gizmos/src/primitives/dim2.rs @@ -38,7 +38,11 @@ pub trait GizmoPrimitive2d { // direction 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self : 'a; fn primitive_2d( @@ -62,7 +66,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { // circle 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -82,7 +90,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> // ellipse 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -102,7 +114,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T // capsule 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -168,8 +184,12 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, // line 2d // /// Builder for configuring the drawing options of [`Line2d`]. -pub struct Line2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Line2dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, direction: Dir2, // Direction of the line @@ -180,7 +200,11 @@ pub struct Line2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { draw_arrow: bool, // decides whether to indicate the direction of the line with an arrow } -impl Line2dBuilder<'_, '_, '_, T> { +impl Line2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the drawing mode of the line (arrow vs. plain line) pub fn draw_arrow(mut self, is_enabled: bool) -> Self { self.draw_arrow = is_enabled; @@ -188,8 +212,12 @@ impl Line2dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { - type Output<'a> = Line2dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Line2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_2d( &mut self, @@ -209,7 +237,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> } } -impl Drop for Line2dBuilder<'_, '_, '_, T> { +impl Drop for Line2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -239,7 +271,11 @@ impl Drop for Line2dBuilder<'_, '_, '_, T> { // plane 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -289,8 +325,12 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T // segment 2d /// Builder for configuring the drawing options of [`Segment2d`]. -pub struct Segment2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Segment2dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, direction: Dir2, // Direction of the line segment half_length: f32, // Half-length of the line segment @@ -302,7 +342,11 @@ pub struct Segment2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { draw_arrow: bool, // decides whether to draw just a line or an arrow } -impl Segment2dBuilder<'_, '_, '_, T> { +impl Segment2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the drawing mode of the line (arrow vs. plain line) pub fn draw_arrow(mut self, is_enabled: bool) -> Self { self.draw_arrow = is_enabled; @@ -310,8 +354,12 @@ impl Segment2dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { - type Output<'a> = Segment2dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Segment2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_2d( &mut self, @@ -334,7 +382,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, } } -impl Drop for Segment2dBuilder<'_, '_, '_, T> { +impl Drop for Segment2dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -354,8 +406,11 @@ impl Drop for Segment2dBuilder<'_, '_, '_, T> { // polyline 2d -impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d> - for Gizmos<'w, 's, T> +impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive2d> + for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, { type Output<'a> = () where Self: 'a; @@ -383,7 +438,11 @@ impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d // boxed polyline 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -410,7 +469,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<' // triangle 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -431,7 +494,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's // rectangle 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -459,8 +526,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, // polygon 2d -impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d> - for Gizmos<'w, 's, T> +impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive2d> + for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, { type Output<'a> = () where Self: 'a; @@ -498,7 +568,11 @@ impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d> // boxed polygon 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( @@ -533,7 +607,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, // regular polygon 2d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive2d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_2d( diff --git a/crates/bevy_gizmos/src/primitives/dim3.rs b/crates/bevy_gizmos/src/primitives/dim3.rs index 025b2f74fa8a7..66924fbb3f007 100644 --- a/crates/bevy_gizmos/src/primitives/dim3.rs +++ b/crates/bevy_gizmos/src/primitives/dim3.rs @@ -35,7 +35,11 @@ pub trait GizmoPrimitive3d { // direction 3d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_3d( @@ -52,8 +56,12 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { // sphere /// Builder for configuring the drawing options of [`Sphere`]. -pub struct SphereBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct SphereBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the sphere radius: f32, @@ -69,7 +77,11 @@ pub struct SphereBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl SphereBuilder<'_, '_, '_, T> { +impl SphereBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to approximate the sphere geometry. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -77,8 +89,12 @@ impl SphereBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = SphereBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = SphereBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -98,7 +114,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> } } -impl Drop for SphereBuilder<'_, '_, '_, T> { +impl Drop for SphereBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -135,8 +155,12 @@ impl Drop for SphereBuilder<'_, '_, '_, T> { // plane 3d /// Builder for configuring the drawing options of [`Plane3d`]. -pub struct Plane3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Plane3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // direction of the normal orthogonal to the plane normal: Dir3, @@ -156,7 +180,11 @@ pub struct Plane3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segment_length: f32, } -impl Plane3dBuilder<'_, '_, '_, T> { +impl Plane3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to hint the plane. pub fn segment_count(mut self, count: usize) -> Self { self.segment_count = count; @@ -176,8 +204,12 @@ impl Plane3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = Plane3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Plane3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -199,7 +231,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T } } -impl Drop for Plane3dBuilder<'_, '_, '_, T> { +impl Drop for Plane3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -243,7 +279,11 @@ impl Drop for Plane3dBuilder<'_, '_, '_, T> { // line 3d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_3d( @@ -271,7 +311,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> // segment 3d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_3d( @@ -294,8 +338,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, // polyline 3d -impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive3d> - for Gizmos<'w, 's, T> +impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive3d> + for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, { type Output<'a> = () where Self: 'a; @@ -321,7 +368,11 @@ impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive3d // boxed polyline 3d -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_3d( @@ -348,7 +399,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<' // cuboid -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ type Output<'a> = () where Self: 'a; fn primitive_3d( @@ -404,8 +459,12 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> // cylinder 3d /// Builder for configuring the drawing options of [`Cylinder`]. -pub struct Cylinder3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Cylinder3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the cylinder radius: f32, @@ -425,7 +484,11 @@ pub struct Cylinder3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl Cylinder3dBuilder<'_, '_, '_, T> { +impl Cylinder3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to approximate the cylinder geometry. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -433,8 +496,12 @@ impl Cylinder3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = Cylinder3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Cylinder3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -455,7 +522,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, } } -impl Drop for Cylinder3dBuilder<'_, '_, '_, T> { +impl Drop for Cylinder3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -501,8 +572,12 @@ impl Drop for Cylinder3dBuilder<'_, '_, '_, T> { // capsule 3d /// Builder for configuring the drawing options of [`Capsule3d`]. -pub struct Capsule3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Capsule3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the capsule radius: f32, @@ -522,7 +597,11 @@ pub struct Capsule3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl Capsule3dBuilder<'_, '_, '_, T> { +impl Capsule3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to approximate the capsule geometry. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -530,8 +609,12 @@ impl Capsule3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = Capsule3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Capsule3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -552,7 +635,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, } } -impl Drop for Capsule3dBuilder<'_, '_, '_, T> { +impl Drop for Capsule3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -594,8 +681,12 @@ impl Drop for Capsule3dBuilder<'_, '_, '_, T> { // cone 3d /// Builder for configuring the drawing options of [`Cone`]. -pub struct Cone3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Cone3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the cone radius: f32, @@ -618,7 +709,11 @@ pub struct Cone3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { height_segments: usize, } -impl Cone3dBuilder<'_, '_, '_, T> { +impl Cone3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to approximate the cone geometry for its base and height. pub fn segments(mut self, segments: usize) -> Self { self.base_segments = segments; @@ -645,8 +740,12 @@ impl Cone3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = Cone3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Cone3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -668,7 +767,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { } } -impl Drop for Cone3dBuilder<'_, '_, '_, T> { +impl Drop for Cone3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -712,8 +815,12 @@ impl Drop for Cone3dBuilder<'_, '_, '_, T> { // conical frustum 3d /// Builder for configuring the drawing options of [`ConicalFrustum`]. -pub struct ConicalFrustum3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct ConicalFrustum3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the top circle radius_top: f32, @@ -735,7 +842,11 @@ pub struct ConicalFrustum3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { segments: usize, } -impl ConicalFrustum3dBuilder<'_, '_, '_, T> { +impl ConicalFrustum3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments used to approximate the curved surfaces. pub fn segments(mut self, segments: usize) -> Self { self.segments = segments; @@ -743,8 +854,12 @@ impl ConicalFrustum3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = ConicalFrustum3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = ConicalFrustum3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -766,7 +881,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w } } -impl Drop for ConicalFrustum3dBuilder<'_, '_, '_, T> { +impl Drop for ConicalFrustum3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; @@ -818,8 +937,12 @@ impl Drop for ConicalFrustum3dBuilder<'_, '_, '_, T> { // torus 3d /// Builder for configuring the drawing options of [`Torus`]. -pub struct Torus3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { - gizmos: &'a mut Gizmos<'w, 's, T>, +pub struct Torus3dBuilder<'a, 'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + gizmos: &'a mut Gizmos<'w, 's, Config, Clear>, // Radius of the minor circle (tube) minor_radius: f32, @@ -841,7 +964,11 @@ pub struct Torus3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> { major_segments: usize, } -impl Torus3dBuilder<'_, '_, '_, T> { +impl Torus3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ /// Set the number of segments in the minor (tube) direction. pub fn minor_segments(mut self, minor_segments: usize) -> Self { self.minor_segments = minor_segments; @@ -855,8 +982,12 @@ impl Torus3dBuilder<'_, '_, '_, T> { } } -impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> { - type Output<'a> = Torus3dBuilder<'a, 'w, 's, T> where Self: 'a; +impl<'w, 's, Config, Clear> GizmoPrimitive3d for Gizmos<'w, 's, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ + type Output<'a> = Torus3dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a; fn primitive_3d( &mut self, @@ -878,7 +1009,11 @@ impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d for Gizmos<'w, 's, T> } } -impl Drop for Torus3dBuilder<'_, '_, '_, T> { +impl Drop for Torus3dBuilder<'_, '_, '_, Config, Clear> +where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ fn drop(&mut self) { if !self.gizmos.enabled { return; diff --git a/crates/bevy_gizmos/src/primitives/helpers.rs b/crates/bevy_gizmos/src/primitives/helpers.rs index 3de0502829536..a60d079066979 100644 --- a/crates/bevy_gizmos/src/primitives/helpers.rs +++ b/crates/bevy_gizmos/src/primitives/helpers.rs @@ -51,15 +51,18 @@ pub(crate) fn circle_coordinates(radius: f32, segments: usize) -> impl Iterator< /// This function draws a semi-sphere at the specified `center` point with the given `rotation`, /// `radius`, and `color`. The `segments` parameter determines the level of detail, and the `top` /// argument specifies the shape of the semi-sphere's tip. -pub(crate) fn draw_semi_sphere( - gizmos: &mut Gizmos<'_, '_, T>, +pub(crate) fn draw_semi_sphere( + gizmos: &mut Gizmos<'_, '_, Config, Clear>, radius: f32, segments: usize, rotation: Quat, center: Vec3, top: Vec3, color: Color, -) { +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ circle_coordinates(radius, segments) .map(|p| Vec3::new(p.x, 0.0, p.y)) .map(rotate_then_translate_3d(rotation, center)) @@ -75,14 +78,17 @@ pub(crate) fn draw_semi_sphere( /// # Note /// /// This function is necessary to use instead of `gizmos.circle` for certain primitives to ensure that points align correctly. For example, the major circles of a torus are drawn with this method, and using `gizmos.circle` would result in the minor circles not being positioned precisely on the major circles' segment points. -pub(crate) fn draw_circle_3d( - gizmos: &mut Gizmos<'_, '_, T>, +pub(crate) fn draw_circle_3d( + gizmos: &mut Gizmos<'_, '_, Config, Clear>, radius: f32, segments: usize, rotation: Quat, translation: Vec3, color: Color, -) { +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ let positions = (0..=segments) .map(|frac| frac as f32 / segments as f32) .map(|percentage| percentage * TAU) @@ -93,15 +99,18 @@ pub(crate) fn draw_circle_3d( } /// Draws the connecting lines of a cylinder between the top circle and the bottom circle. -pub(crate) fn draw_cylinder_vertical_lines( - gizmos: &mut Gizmos<'_, '_, T>, +pub(crate) fn draw_cylinder_vertical_lines( + gizmos: &mut Gizmos<'_, '_, Config, Clear>, radius: f32, segments: usize, half_height: f32, rotation: Quat, center: Vec3, color: Color, -) { +) where + Config: GizmoConfigGroup, + Clear: 'static + Send + Sync, +{ circle_coordinates(radius, segments) .map(move |point_2d| { [1.0, -1.0]