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<Clear>` and the requisite systems:
- `propagate_gizmos::<Clear>` 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.
This commit is contained in:
Aceeri 2024-04-22 17:16:12 -07:00 committed by GitHub
parent fcd87b2528
commit b1ab036329
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 786 additions and 208 deletions

View File

@ -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"

View File

@ -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<Color>,
) -> 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<usize>,
}
impl<T: GizmoConfigGroup> Arc2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Arc2dBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for Arc2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<Color>,
) -> 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<Color>,
) -> 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<Color>,
) -> 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<Color>,
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<usize>,
}
impl<T: GizmoConfigGroup> Arc3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Arc3dBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for Arc3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> Drop for Arc3dBuilder<'_, '_, '_, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
fn drop(&mut self) {
if !self.gizmos.enabled {
return;

View File

@ -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<T: GizmoConfigGroup> ArrowBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> ArrowBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for ArrowBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<Color>,
) -> 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<Color>,
) -> 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`.
///

View File

@ -19,7 +19,11 @@ fn ellipse_inner(half_size: Vec2, segments: usize) -> impl Iterator<Item = Vec2>
})
}
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<Color>,
) -> 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<Color>,
) -> 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<Color>,
) -> 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<Color>,
) -> 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<T: GizmoConfigGroup> EllipseBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> EllipseBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for EllipseBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> Ellipse2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Ellipse2dBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for Ellipse2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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;

View File

@ -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<T: GizmoConfigGroup> {
/// Storage of gizmo primitives.
#[derive(Resource)]
pub struct GizmoStorage<Config, Clear> {
pub(crate) list_positions: Vec<Vec3>,
pub(crate) list_colors: Vec<LinearRgba>,
pub(crate) strip_positions: Vec<Vec3>,
pub(crate) strip_colors: Vec<LinearRgba>,
marker: PhantomData<T>,
marker: PhantomData<(Config, Clear)>,
}
impl<Config, Clear> Default for GizmoStorage<Config, Clear> {
fn default() -> Self {
Self {
list_positions: default(),
list_colors: default(),
strip_positions: default(),
strip_colors: default(),
marker: PhantomData,
}
}
}
impl<Config, Clear> GizmoStorage<Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
/// Combine the other gizmo storage with this one.
pub fn append_storage<OtherConfig, OtherClear>(
&mut self,
other: &GizmoStorage<OtherConfig, OtherClear>,
) {
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<OtherConfig, OtherClear>(
&mut self,
other: &mut GizmoStorage<OtherConfig, OtherClear>,
) {
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<Clear>(PhantomData<Clear>);
/// 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<T>>,
/// 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::<GizmoStorage<DefaultGizmoConfigGroup, MyContext>>()
/// // 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::<DefaultGizmoConfigGroup, MyContext>)
/// // If not running multiple times, put this with [`start_gizmo_context`].
/// .add_systems(StartOfRun, clear_gizmo_context::<DefaultGizmoConfigGroup, MyContext>)
/// // If not running multiple times, put this with [`end_gizmo_context`].
/// .add_systems(EndOfRun, collect_requested_gizmos::<DefaultGizmoConfigGroup, MyContext>)
/// .add_systems(EndOfMyContext, end_gizmo_context::<DefaultGizmoConfigGroup, MyContext>)
/// .add_systems(
/// Last,
/// propagate_gizmos::<DefaultGizmoConfigGroup, MyContext>.before(UpdateGizmoMeshes),
/// );
/// }
/// }
/// ```
pub struct Gizmos<'w, 's, Config = DefaultGizmoConfigGroup, Clear = ()>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
buffer: Deferred<'s, GizmoBuffer<Config, Clear>>,
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<T> = (
Deferred<'static, GizmoBuffer<T>>,
type GizmosState<Config, Clear> = (
Deferred<'static, GizmoBuffer<Config, Clear>>,
Res<'static, GizmoConfigStore>,
);
#[doc(hidden)]
pub struct GizmosFetchState<T: GizmoConfigGroup> {
state: <GizmosState<T> as SystemParam>::State,
pub struct GizmosFetchState<Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
state: <GizmosState<Config, Clear> as SystemParam>::State,
}
#[allow(unsafe_code)]
// SAFETY: All methods are delegated to existing `SystemParam` implementations
unsafe impl<T: GizmoConfigGroup> SystemParam for Gizmos<'_, '_, T> {
type State = GizmosFetchState<T>;
type Item<'w, 's> = Gizmos<'w, 's, T>;
unsafe impl<Config, Clear> SystemParam for Gizmos<'_, '_, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
type State = GizmosFetchState<Config, Clear>;
type Item<'w, 's> = Gizmos<'w, 's, Config, Clear>;
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
GizmosFetchState {
state: GizmosState::<T>::init_state(world, system_meta),
state: GizmosState::<Config, Clear>::init_state(world, system_meta),
}
}
@ -68,11 +179,13 @@ unsafe impl<T: GizmoConfigGroup> 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::<T>::new_archetype(&mut state.state, archetype, system_meta) };
unsafe {
GizmosState::<Config, Clear>::new_archetype(&mut state.state, archetype, system_meta);
};
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
GizmosState::<T>::apply(&mut state.state, system_meta, world);
GizmosState::<Config, Clear>::apply(&mut state.state, system_meta, world);
}
unsafe fn get_param<'w, 's>(
@ -83,12 +196,17 @@ unsafe impl<T: GizmoConfigGroup> SystemParam for Gizmos<'_, '_, T> {
) -> Self::Item<'w, 's> {
// SAFETY: Delegated to existing `SystemParam` implementations
let (f0, f1) = unsafe {
GizmosState::<T>::get_param(&mut state.state, system_meta, world, change_tick)
GizmosState::<Config, Clear>::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::<T>();
let (config, config_ext) = f1.into_inner().config::<Config>();
Gizmos {
buffer: f0,
enabled: config.enabled,
@ -100,25 +218,50 @@ unsafe impl<T: GizmoConfigGroup> 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<T>>: ReadOnlySystemParam,
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
Deferred<'s, GizmoBuffer<Config, Clear>>: ReadOnlySystemParam,
Res<'w, GizmoConfigStore>: ReadOnlySystemParam,
{
}
#[derive(Default)]
struct GizmoBuffer<T: GizmoConfigGroup> {
struct GizmoBuffer<Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
list_positions: Vec<Vec3>,
list_colors: Vec<LinearRgba>,
strip_positions: Vec<Vec3>,
strip_colors: Vec<LinearRgba>,
marker: PhantomData<T>,
marker: PhantomData<(Config, Clear)>,
}
impl<T: GizmoConfigGroup> SystemBuffer for GizmoBuffer<T> {
impl<Config, Clear> Default for GizmoBuffer<Config, Clear>
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<Config, Clear> SystemBuffer for GizmoBuffer<Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
fn apply(&mut self, _system_meta: &SystemMeta, world: &mut World) {
let mut storage = world.resource_mut::<GizmoStorage<T>>();
let mut storage = world.resource_mut::<GizmoStorage<Config, Clear>>();
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<T: GizmoConfigGroup> SystemBuffer for GizmoBuffer<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 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<Color>,
) -> 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<T: GizmoConfigGroup> SphereBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> SphereBuilder<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for SphereBuilder<'_, '_, '_, T> {
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
fn drop(&mut self) {
if !self.gizmos.enabled {
return;

View File

@ -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<T: GizmoConfigGroup> GridBuilder3d<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> GridBuilder3d<'_, '_, '_, T> {
self
}
}
impl<T: GizmoConfigGroup> GridBuilder2d<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> GridBuilder2d<'_, '_, '_, T> {
}
}
impl<T: GizmoConfigGroup> Drop for GridBuilder3d<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Drop for GridBuilder3d<'_, '_, '_, T> {
);
}
}
impl<T: GizmoConfigGroup> Drop for GridBuilder2d<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<LinearRgba>,
) -> 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<LinearRgba>,
) -> 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<LinearRgba>,
) -> 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<T: GizmoConfigGroup>(
gizmos: &mut Gizmos<'_, '_, T>,
fn draw_grid<Config, Clear>(
gizmos: &mut Gizmos<'_, '_, Config, Clear>,
position: Vec3,
rotation: Quat,
spacing: Vec3,
@ -329,7 +360,10 @@ fn draw_grid<T: GizmoConfigGroup>(
skew: Vec3,
outer_edges: [bool; 3],
color: LinearRgba,
) {
) where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
if !gizmos.enabled {
return;
}

View File

@ -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<T>()` 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&lt;T&gt;](crate::gizmos::Gizmos).
/// Registers [`GizmoConfigGroup`] in the app enabling the use of [Gizmos&lt;Config&gt;](crate::gizmos::Gizmos).
///
/// Configurations can be set using the [`GizmoConfigStore`] [`Resource`].
fn init_gizmo_group<T: GizmoConfigGroup + Default>(&mut self) -> &mut Self;
fn init_gizmo_group<Config: GizmoConfigGroup>(&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<T: GizmoConfigGroup>(
fn insert_gizmo_config<Config: GizmoConfigGroup>(
&mut self,
group: T,
group: Config,
config: GizmoConfig,
) -> &mut Self;
}
impl AppGizmoBuilder for App {
fn init_gizmo_group<T: GizmoConfigGroup + Default>(&mut self) -> &mut Self {
if self.world().contains_resource::<GizmoStorage<T>>() {
fn init_gizmo_group<Config: GizmoConfigGroup>(&mut self) -> &mut Self {
if self.world().contains_resource::<GizmoStorage<Config, ()>>() {
return self;
}
self.world_mut()
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
.register::<Config>();
let mut handles = self
.world_mut()
.get_resource_or_insert_with::<LineGizmoHandles>(Default::default);
handles.list.insert(TypeId::of::<T>(), None);
handles.strip.insert(TypeId::of::<T>(), None);
self.init_resource::<GizmoStorage<T>>()
.add_systems(Last, update_gizmo_meshes::<T>);
handles.list.insert(TypeId::of::<Config>(), None);
handles.strip.insert(TypeId::of::<Config>(), None);
self.world_mut()
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
.register::<T>();
self.init_resource::<GizmoStorage<Config, ()>>()
.init_resource::<GizmoStorage<Config, Fixed>>()
.init_resource::<GizmoStorage<Config, Swap<Fixed>>>()
.add_systems(
RunFixedMainLoop,
start_gizmo_context::<Config, Fixed>.before(bevy_time::run_fixed_main_schedule),
)
.add_systems(FixedFirst, clear_gizmo_context::<Config, Fixed>)
.add_systems(FixedLast, collect_requested_gizmos::<Config, Fixed>)
.add_systems(
RunFixedMainLoop,
end_gizmo_context::<Config, Fixed>.after(bevy_time::run_fixed_main_schedule),
)
.add_systems(
Last,
(
propagate_gizmos::<Config, Fixed>.before(UpdateGizmoMeshes),
update_gizmo_meshes::<Config>.in_set(UpdateGizmoMeshes),
),
);
self
}
fn insert_gizmo_group<T: GizmoConfigGroup>(
fn insert_gizmo_config<Config: GizmoConfigGroup>(
&mut self,
group: T,
group: Config,
config: GizmoConfig,
) -> &mut Self {
self.init_gizmo_group::<Config>();
self.world_mut()
.get_resource_or_insert_with::<GizmoConfigStore>(Default::default)
.insert(config, group);
if self.world().contains_resource::<GizmoStorage<T>>() {
return self;
}
let mut handles = self
.world_mut()
.get_resource_or_insert_with::<LineGizmoHandles>(Default::default);
handles.list.insert(TypeId::of::<T>(), None);
handles.strip.insert(TypeId::of::<T>(), None);
self.init_resource::<GizmoStorage<T>>()
.add_systems(Last, update_gizmo_meshes::<T>);
self
}
}
@ -262,15 +271,87 @@ struct LineGizmoHandles {
strip: TypeIdMap<Option<Handle<LineGizmo>>>,
}
fn update_gizmo_meshes<T: GizmoConfigGroup>(
/// 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<Config, Clear>(
mut swap: ResMut<GizmoStorage<Config, Swap<Clear>>>,
mut default: ResMut<GizmoStorage<Config, ()>>,
) 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<Clear>`] gizmo storage.
///
/// This must be called before [`UpdateGizmoMeshes`] in the [`Last`] schedule.
pub fn end_gizmo_context<Config, Clear>(
mut swap: ResMut<GizmoStorage<Config, Swap<Clear>>>,
mut default: ResMut<GizmoStorage<Config, ()>>,
) 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<Config, Clear>(
mut update: ResMut<GizmoStorage<Config, ()>>,
mut context: ResMut<GizmoStorage<Config, Clear>>,
) where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
context.append_storage(&update);
update.clear();
}
/// Clear out the contextual gizmos.
pub fn clear_gizmo_context<Config, Clear>(mut context: ResMut<GizmoStorage<Config, Clear>>)
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<Config, Clear>(
mut update_storage: ResMut<GizmoStorage<Config, ()>>,
contextual_storage: Res<GizmoStorage<Config, Clear>>,
) 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<Config: GizmoConfigGroup>(
mut line_gizmos: ResMut<Assets<LineGizmo>>,
mut handles: ResMut<LineGizmoHandles>,
mut storage: ResMut<GizmoStorage<T>>,
mut storage: ResMut<GizmoStorage<Config, ()>>,
config_store: Res<GizmoConfigStore>,
) {
if storage.list_positions.is_empty() {
handles.list.insert(TypeId::of::<T>(), None);
} else if let Some(handle) = handles.list.get_mut(&TypeId::of::<T>()) {
handles.list.insert(TypeId::of::<Config>(), None);
} else if let Some(handle) = handles.list.get_mut(&TypeId::of::<Config>()) {
if let Some(handle) = handle {
let list = line_gizmos.get_mut(handle.id()).unwrap();
@ -289,10 +370,10 @@ fn update_gizmo_meshes<T: GizmoConfigGroup>(
}
}
let (config, _) = config_store.config::<T>();
let (config, _) = config_store.config::<Config>();
if storage.strip_positions.is_empty() {
handles.strip.insert(TypeId::of::<T>(), None);
} else if let Some(handle) = handles.strip.get_mut(&TypeId::of::<T>()) {
handles.strip.insert(TypeId::of::<Config>(), None);
} else if let Some(handle) = handles.strip.get_mut(&TypeId::of::<Config>()) {
if let Some(handle) = handle {
let strip = line_gizmos.get_mut(handle.id()).unwrap();

View File

@ -38,7 +38,11 @@ pub trait GizmoPrimitive2d<P: Primitive2d> {
// direction 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Dir2> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Dir2> 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<Dir2> for Gizmos<'w, 's, T> {
// circle 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Circle> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Circle> 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<Circle> for Gizmos<'w, 's, T>
// ellipse 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Ellipse> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Ellipse> 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<Ellipse> for Gizmos<'w, 's, T
// capsule 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Capsule2d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Capsule2d> 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<Capsule2d> 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<T: GizmoConfigGroup> Line2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Line2dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Line2d> for Gizmos<'w, 's, T> {
type Output<'a> = Line2dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Line2d> 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<Line2d> for Gizmos<'w, 's, T>
}
}
impl<T: GizmoConfigGroup> Drop for Line2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Drop for Line2dBuilder<'_, '_, '_, T> {
// plane 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Plane2d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Plane2d> 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<Plane2d> 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<T: GizmoConfigGroup> Segment2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Segment2dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Segment2d> for Gizmos<'w, 's, T> {
type Output<'a> = Segment2dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Segment2d> 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<Segment2d> for Gizmos<'w, 's,
}
}
impl<T: GizmoConfigGroup> Drop for Segment2dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Drop for Segment2dBuilder<'_, '_, '_, T> {
// polyline 2d
impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d<Polyline2d<N>>
for Gizmos<'w, 's, T>
impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive2d<Polyline2d<N>>
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<Polyline2d<N>
// boxed polyline 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<BoxedPolyline2d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<BoxedPolyline2d> 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<BoxedPolyline2d> for Gizmos<'
// triangle 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Triangle2d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Triangle2d> 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<Triangle2d> for Gizmos<'w, 's
// rectangle 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<Rectangle> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Rectangle> 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<Rectangle> for Gizmos<'w, 's,
// polygon 2d
impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive2d<Polygon<N>>
for Gizmos<'w, 's, T>
impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive2d<Polygon<N>>
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<Polygon<N>>
// boxed polygon 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<BoxedPolygon> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<BoxedPolygon> 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<BoxedPolygon> for Gizmos<'w,
// regular polygon 2d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive2d<RegularPolygon> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive2d<RegularPolygon> for Gizmos<'w, 's, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
type Output<'a> = () where Self: 'a;
fn primitive_2d(

View File

@ -35,7 +35,11 @@ pub trait GizmoPrimitive3d<P: Primitive3d> {
// direction 3d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Dir3> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Dir3> 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<Dir3> 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<T: GizmoConfigGroup> SphereBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> SphereBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Sphere> for Gizmos<'w, 's, T> {
type Output<'a> = SphereBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Sphere> 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<Sphere> for Gizmos<'w, 's, T>
}
}
impl<T: GizmoConfigGroup> Drop for SphereBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> Plane3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Plane3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Plane3d> for Gizmos<'w, 's, T> {
type Output<'a> = Plane3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Plane3d> 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<Plane3d> for Gizmos<'w, 's, T
}
}
impl<T: GizmoConfigGroup> Drop for Plane3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Drop for Plane3dBuilder<'_, '_, '_, T> {
// line 3d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Line3d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Line3d> 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<Line3d> for Gizmos<'w, 's, T>
// segment 3d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Segment3d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Segment3d> 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<Segment3d> for Gizmos<'w, 's,
// polyline 3d
impl<'w, 's, const N: usize, T: GizmoConfigGroup> GizmoPrimitive3d<Polyline3d<N>>
for Gizmos<'w, 's, T>
impl<'w, 's, const N: usize, Config, Clear> GizmoPrimitive3d<Polyline3d<N>>
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<Polyline3d<N>
// boxed polyline 3d
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<BoxedPolyline3d> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive3d<BoxedPolyline3d> 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<BoxedPolyline3d> for Gizmos<'
// cuboid
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Cuboid> for Gizmos<'w, 's, T> {
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Cuboid> 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<Cuboid> 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<T: GizmoConfigGroup> Cylinder3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Cylinder3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Cylinder> for Gizmos<'w, 's, T> {
type Output<'a> = Cylinder3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Cylinder> 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<Cylinder> for Gizmos<'w, 's,
}
}
impl<T: GizmoConfigGroup> Drop for Cylinder3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> Capsule3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Capsule3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Capsule3d> for Gizmos<'w, 's, T> {
type Output<'a> = Capsule3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Capsule3d> 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<Capsule3d> for Gizmos<'w, 's,
}
}
impl<T: GizmoConfigGroup> Drop for Capsule3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> Cone3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Cone3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Cone> for Gizmos<'w, 's, T> {
type Output<'a> = Cone3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Cone> 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<Cone> for Gizmos<'w, 's, T> {
}
}
impl<T: GizmoConfigGroup> Drop for Cone3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> ConicalFrustum3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> ConicalFrustum3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<ConicalFrustum> for Gizmos<'w, 's, T> {
type Output<'a> = ConicalFrustum3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<ConicalFrustum> 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<ConicalFrustum> for Gizmos<'w
}
}
impl<T: GizmoConfigGroup> Drop for ConicalFrustum3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> 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<T: GizmoConfigGroup> Torus3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> 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<T: GizmoConfigGroup> Torus3dBuilder<'_, '_, '_, T> {
}
}
impl<'w, 's, T: GizmoConfigGroup> GizmoPrimitive3d<Torus> for Gizmos<'w, 's, T> {
type Output<'a> = Torus3dBuilder<'a, 'w, 's, T> where Self: 'a;
impl<'w, 's, Config, Clear> GizmoPrimitive3d<Torus> 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<Torus> for Gizmos<'w, 's, T>
}
}
impl<T: GizmoConfigGroup> Drop for Torus3dBuilder<'_, '_, '_, T> {
impl<Config, Clear> Drop for Torus3dBuilder<'_, '_, '_, Config, Clear>
where
Config: GizmoConfigGroup,
Clear: 'static + Send + Sync,
{
fn drop(&mut self) {
if !self.gizmos.enabled {
return;

View File

@ -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<T: GizmoConfigGroup>(
gizmos: &mut Gizmos<'_, '_, T>,
pub(crate) fn draw_semi_sphere<Config, Clear>(
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<T: GizmoConfigGroup>(
/// # 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<T: GizmoConfigGroup>(
gizmos: &mut Gizmos<'_, '_, T>,
pub(crate) fn draw_circle_3d<Config, Clear>(
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<T: GizmoConfigGroup>(
}
/// Draws the connecting lines of a cylinder between the top circle and the bottom circle.
pub(crate) fn draw_cylinder_vertical_lines<T: GizmoConfigGroup>(
gizmos: &mut Gizmos<'_, '_, T>,
pub(crate) fn draw_cylinder_vertical_lines<Config, Clear>(
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]