2023-10-06 00:31:10 +00:00
|
|
|
//! A module for the [`Gizmos`] [`SystemParam`].
|
2023-03-28 20:58:02 +00:00
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
use std::{iter, marker::PhantomData};
|
2023-03-20 20:57:54 +00:00
|
|
|
|
2023-11-20 09:47:50 +00:00
|
|
|
use crate::circles::DEFAULT_CIRCLE_SEGMENTS;
|
2024-02-26 23:50:33 +00:00
|
|
|
use bevy_color::LinearRgba;
|
2023-03-20 20:57:54 +00:00
|
|
|
use bevy_ecs::{
|
2024-01-18 15:52:50 +00:00
|
|
|
component::Tick,
|
|
|
|
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
|
|
|
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
2023-03-20 20:57:54 +00:00
|
|
|
};
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
use bevy_math::{Dir3, Mat2, Quat, Vec2, Vec3};
|
2024-02-24 21:35:32 +00:00
|
|
|
use bevy_render::color::LegacyColor;
|
2023-04-24 15:23:06 +00:00
|
|
|
use bevy_transform::TransformPoint;
|
2023-03-20 20:57:54 +00:00
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
use crate::{
|
|
|
|
config::GizmoConfigGroup,
|
|
|
|
config::{DefaultGizmoConfigGroup, GizmoConfigStore},
|
|
|
|
prelude::GizmoConfig,
|
|
|
|
};
|
|
|
|
|
2023-03-20 20:57:54 +00:00
|
|
|
type PositionItem = [f32; 3];
|
|
|
|
|
|
|
|
#[derive(Resource, Default)]
|
2024-01-18 15:52:50 +00:00
|
|
|
pub(crate) struct GizmoStorage<T: GizmoConfigGroup> {
|
2024-02-26 23:50:33 +00:00
|
|
|
pub(crate) list_positions: Vec<PositionItem>,
|
|
|
|
pub(crate) list_colors: Vec<LinearRgba>,
|
|
|
|
pub(crate) strip_positions: Vec<PositionItem>,
|
|
|
|
pub(crate) strip_colors: Vec<LinearRgba>,
|
2024-01-18 15:52:50 +00:00
|
|
|
marker: PhantomData<T>,
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-10-06 00:31:10 +00:00
|
|
|
/// A [`SystemParam`] for drawing gizmos.
|
2023-07-31 19:14:52 +00:00
|
|
|
///
|
|
|
|
/// 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.
|
2024-01-18 15:52:50 +00:00
|
|
|
pub struct Gizmos<'w, 's, T: GizmoConfigGroup = DefaultGizmoConfigGroup> {
|
|
|
|
buffer: Deferred<'s, GizmoBuffer<T>>,
|
|
|
|
pub(crate) enabled: bool,
|
|
|
|
/// The currently used [`GizmoConfig`]
|
|
|
|
pub config: &'w GizmoConfig,
|
|
|
|
/// The currently used [`GizmoConfigGroup`]
|
|
|
|
pub config_ext: &'w T,
|
|
|
|
}
|
|
|
|
|
|
|
|
type GizmosState<T> = (
|
|
|
|
Deferred<'static, GizmoBuffer<T>>,
|
|
|
|
Res<'static, GizmoConfigStore>,
|
|
|
|
);
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct GizmosFetchState<T: GizmoConfigGroup> {
|
|
|
|
state: <GizmosState<T> as SystemParam>::State,
|
|
|
|
}
|
2024-01-28 23:18:11 +00:00
|
|
|
// SAFETY: All methods are delegated to existing `SystemParam` implementations
|
2024-01-18 15:52:50 +00:00
|
|
|
unsafe impl<T: GizmoConfigGroup> SystemParam for Gizmos<'_, '_, T> {
|
|
|
|
type State = GizmosFetchState<T>;
|
|
|
|
type Item<'w, 's> = Gizmos<'w, 's, T>;
|
|
|
|
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
|
|
|
|
GizmosFetchState {
|
|
|
|
state: GizmosState::<T>::init_state(world, system_meta),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn new_archetype(
|
|
|
|
state: &mut Self::State,
|
|
|
|
archetype: &bevy_ecs::archetype::Archetype,
|
|
|
|
system_meta: &mut SystemMeta,
|
|
|
|
) {
|
|
|
|
GizmosState::<T>::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);
|
|
|
|
}
|
|
|
|
unsafe fn get_param<'w, 's>(
|
|
|
|
state: &'s mut Self::State,
|
|
|
|
system_meta: &SystemMeta,
|
|
|
|
world: UnsafeWorldCell<'w>,
|
|
|
|
change_tick: Tick,
|
|
|
|
) -> Self::Item<'w, 's> {
|
2024-01-28 23:18:11 +00:00
|
|
|
// SAFETY: Delegated to existing `SystemParam` implementations
|
|
|
|
let (f0, f1) = unsafe {
|
|
|
|
GizmosState::<T>::get_param(&mut state.state, system_meta, world, change_tick)
|
|
|
|
};
|
2024-01-18 15:52:50 +00:00
|
|
|
// 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>();
|
|
|
|
Gizmos {
|
|
|
|
buffer: f0,
|
|
|
|
enabled: config.enabled,
|
|
|
|
config,
|
|
|
|
config_ext,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Safety: Each field is `ReadOnlySystemParam`, and Gizmos SystemParam does not mutate world
|
|
|
|
unsafe impl<'w, 's, T: GizmoConfigGroup> ReadOnlySystemParam for Gizmos<'w, 's, T>
|
|
|
|
where
|
|
|
|
Deferred<'s, GizmoBuffer<T>>: ReadOnlySystemParam,
|
|
|
|
Res<'w, GizmoConfigStore>: ReadOnlySystemParam,
|
|
|
|
{
|
2023-03-28 20:58:02 +00:00
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
|
|
|
|
#[derive(Default)]
|
2024-01-18 15:52:50 +00:00
|
|
|
struct GizmoBuffer<T: GizmoConfigGroup> {
|
2023-03-20 20:57:54 +00:00
|
|
|
list_positions: Vec<PositionItem>,
|
2024-02-26 23:50:33 +00:00
|
|
|
list_colors: Vec<LinearRgba>,
|
2023-03-20 20:57:54 +00:00
|
|
|
strip_positions: Vec<PositionItem>,
|
2024-02-26 23:50:33 +00:00
|
|
|
strip_colors: Vec<LinearRgba>,
|
2024-01-18 15:52:50 +00:00
|
|
|
marker: PhantomData<T>,
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
impl<T: GizmoConfigGroup> SystemBuffer for GizmoBuffer<T> {
|
2023-03-20 20:57:54 +00:00
|
|
|
fn apply(&mut self, _system_meta: &SystemMeta, world: &mut World) {
|
2024-01-18 15:52:50 +00:00
|
|
|
let mut storage = world.resource_mut::<GizmoStorage<T>>();
|
2023-03-20 20:57:54 +00:00
|
|
|
storage.list_positions.append(&mut self.list_positions);
|
|
|
|
storage.list_colors.append(&mut self.list_colors);
|
|
|
|
storage.strip_positions.append(&mut self.strip_positions);
|
|
|
|
storage.strip_colors.append(&mut self.strip_colors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D from `start` to `end`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.line(Vec3::ZERO, Vec3::X, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn line(&mut self, start: Vec3, end: Vec3, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.extend_list_positions([start, end]);
|
|
|
|
self.add_list_color(color, 2);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D with a color gradient from `start` to `end`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.line_gradient(Vec3::ZERO, Vec3::X, LegacyColor::GREEN, LegacyColor::RED);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn line_gradient(
|
|
|
|
&mut self,
|
|
|
|
start: Vec3,
|
|
|
|
end: Vec3,
|
|
|
|
start_color: LegacyColor,
|
|
|
|
end_color: LegacyColor,
|
|
|
|
) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.extend_list_positions([start, end]);
|
|
|
|
self.extend_list_colors([start_color, end_color]);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D from `start` to `start + vector`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.ray(Vec3::Y, Vec3::X, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn ray(&mut self, start: Vec3, vector: Vec3, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line(start, start + vector, color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D with a color gradient from `start` to `start + vector`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.ray_gradient(Vec3::Y, Vec3::X, LegacyColor::GREEN, LegacyColor::RED);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn ray_gradient(
|
|
|
|
&mut self,
|
|
|
|
start: Vec3,
|
|
|
|
vector: Vec3,
|
2024-02-24 21:35:32 +00:00
|
|
|
start_color: LegacyColor,
|
|
|
|
end_color: LegacyColor,
|
2023-03-20 20:57:54 +00:00
|
|
|
) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line_gradient(start, start + vector, start_color, end_color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D made of straight segments between the points.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.linestrip([Vec3::ZERO, Vec3::X, Vec3::Y], LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn linestrip(&mut self, positions: impl IntoIterator<Item = Vec3>, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-08-25 12:34:24 +00:00
|
|
|
self.extend_strip_positions(positions);
|
2023-03-28 20:58:02 +00:00
|
|
|
let len = self.buffer.strip_positions.len();
|
2024-02-26 23:50:33 +00:00
|
|
|
self.buffer.strip_colors.resize(len - 1, color.into());
|
|
|
|
self.buffer.strip_colors.push(LinearRgba::NAN);
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 3D made of straight segments between the points, with a color gradient.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the lines need to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
|
|
|
/// gizmos.linestrip_gradient([
|
2024-02-24 21:35:32 +00:00
|
|
|
/// (Vec3::ZERO, LegacyColor::GREEN),
|
|
|
|
/// (Vec3::X, LegacyColor::RED),
|
|
|
|
/// (Vec3::Y, LegacyColor::BLUE)
|
2023-03-28 20:58:02 +00:00
|
|
|
/// ]);
|
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn linestrip_gradient(&mut self, points: impl IntoIterator<Item = (Vec3, LegacyColor)>) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
let points = points.into_iter();
|
|
|
|
|
2023-03-28 20:58:02 +00:00
|
|
|
let GizmoBuffer {
|
|
|
|
strip_positions,
|
|
|
|
strip_colors,
|
|
|
|
..
|
|
|
|
} = &mut *self.buffer;
|
|
|
|
|
2023-03-20 20:57:54 +00:00
|
|
|
let (min, _) = points.size_hint();
|
2023-03-28 20:58:02 +00:00
|
|
|
strip_positions.reserve(min);
|
|
|
|
strip_colors.reserve(min);
|
2023-03-20 20:57:54 +00:00
|
|
|
|
|
|
|
for (position, color) in points {
|
2023-03-28 20:58:02 +00:00
|
|
|
strip_positions.push(position.to_array());
|
2024-02-26 23:50:33 +00:00
|
|
|
strip_colors.push(color.into());
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-03-28 20:58:02 +00:00
|
|
|
strip_positions.push([f32::NAN; 3]);
|
2024-02-26 23:50:33 +00:00
|
|
|
strip_colors.push(LinearRgba::NAN);
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the sphere needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.sphere(Vec3::ZERO, Quat::IDENTITY, 1., LegacyColor::BLACK);
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// // Each circle has 32 line-segments by default.
|
|
|
|
/// // You may want to increase this for larger spheres.
|
|
|
|
/// gizmos
|
2024-02-24 21:35:32 +00:00
|
|
|
/// .sphere(Vec3::ZERO, Quat::IDENTITY, 5., LegacyColor::BLACK)
|
2023-03-28 20:58:02 +00:00
|
|
|
/// .circle_segments(64);
|
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn sphere(
|
|
|
|
&mut self,
|
|
|
|
position: Vec3,
|
|
|
|
rotation: Quat,
|
|
|
|
radius: f32,
|
2024-02-24 21:35:32 +00:00
|
|
|
color: LegacyColor,
|
2024-01-18 15:52:50 +00:00
|
|
|
) -> SphereBuilder<'_, 'w, 's, T> {
|
2023-03-20 20:57:54 +00:00
|
|
|
SphereBuilder {
|
2023-03-28 20:58:02 +00:00
|
|
|
gizmos: self,
|
2023-03-20 20:57:54 +00:00
|
|
|
position,
|
|
|
|
rotation,
|
|
|
|
radius,
|
|
|
|
color,
|
|
|
|
circle_segments: DEFAULT_CIRCLE_SEGMENTS,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a wireframe rectangle in 3D.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the rectangle needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.rect(Vec3::ZERO, Quat::IDENTITY, Vec2::ONE, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn rect(&mut self, position: Vec3, rotation: Quat, size: Vec2, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2.extend(0.));
|
|
|
|
self.linestrip([tl, tr, br, bl, tl], color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a wireframe cube in 3D.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the cube needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
2023-04-24 15:23:06 +00:00
|
|
|
/// # use bevy_transform::prelude::*;
|
2023-03-28 20:58:02 +00:00
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.cuboid(Transform::IDENTITY, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn cuboid(&mut self, transform: impl TransformPoint, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-04-24 15:23:06 +00:00
|
|
|
let rect = rect_inner(Vec2::ONE);
|
2023-03-20 20:57:54 +00:00
|
|
|
// Front
|
2023-04-24 15:23:06 +00:00
|
|
|
let [tlf, trf, brf, blf] = rect.map(|vec2| transform.transform_point(vec2.extend(0.5)));
|
2023-03-20 20:57:54 +00:00
|
|
|
// Back
|
2023-04-24 15:23:06 +00:00
|
|
|
let [tlb, trb, brb, blb] = rect.map(|vec2| transform.transform_point(vec2.extend(-0.5)));
|
|
|
|
|
|
|
|
let strip_positions = [
|
|
|
|
tlf, trf, brf, blf, tlf, // Front
|
|
|
|
tlb, trb, brb, blb, tlb, // Back
|
|
|
|
];
|
|
|
|
self.linestrip(strip_positions, color);
|
2023-03-20 20:57:54 +00:00
|
|
|
|
2023-04-24 15:23:06 +00:00
|
|
|
let list_positions = [
|
|
|
|
trf, trb, brf, brb, blf, blb, // Front to back
|
2023-03-20 20:57:54 +00:00
|
|
|
];
|
2023-04-24 15:23:06 +00:00
|
|
|
self.extend_list_positions(list_positions);
|
|
|
|
self.add_list_color(color, 6);
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D from `start` to `end`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.line_2d(Vec2::ZERO, Vec2::X, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn line_2d(&mut self, start: Vec2, end: Vec2, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line(start.extend(0.), end.extend(0.), color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D with a color gradient from `start` to `end`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.line_gradient_2d(Vec2::ZERO, Vec2::X, LegacyColor::GREEN, LegacyColor::RED);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn line_gradient_2d(
|
|
|
|
&mut self,
|
|
|
|
start: Vec2,
|
|
|
|
end: Vec2,
|
2024-02-24 21:35:32 +00:00
|
|
|
start_color: LegacyColor,
|
|
|
|
end_color: LegacyColor,
|
2023-03-20 20:57:54 +00:00
|
|
|
) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line_gradient(start.extend(0.), end.extend(0.), start_color, end_color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D made of straight segments between the points.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.linestrip_2d([Vec2::ZERO, Vec2::X, Vec2::Y], LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn linestrip_2d(&mut self, positions: impl IntoIterator<Item = Vec2>, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.linestrip(positions.into_iter().map(|vec2| vec2.extend(0.)), color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D made of straight segments between the points, with a color gradient.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
|
|
|
/// gizmos.linestrip_gradient_2d([
|
2024-02-24 21:35:32 +00:00
|
|
|
/// (Vec2::ZERO, LegacyColor::GREEN),
|
|
|
|
/// (Vec2::X, LegacyColor::RED),
|
|
|
|
/// (Vec2::Y, LegacyColor::BLUE)
|
2023-03-28 20:58:02 +00:00
|
|
|
/// ]);
|
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn linestrip_gradient_2d(
|
|
|
|
&mut self,
|
|
|
|
positions: impl IntoIterator<Item = (Vec2, LegacyColor)>,
|
|
|
|
) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.linestrip_gradient(
|
|
|
|
positions
|
|
|
|
.into_iter()
|
|
|
|
.map(|(vec2, color)| (vec2.extend(0.), color)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D from `start` to `start + vector`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.ray_2d(Vec2::Y, Vec2::X, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn ray_2d(&mut self, start: Vec2, vector: Vec2, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line_2d(start, start + vector, color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a line in 2D with a color gradient from `start` to `start + vector`.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the line needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.line_gradient(Vec3::Y, Vec3::X, LegacyColor::GREEN, LegacyColor::RED);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn ray_gradient_2d(
|
|
|
|
&mut self,
|
|
|
|
start: Vec2,
|
|
|
|
vector: Vec2,
|
2024-02-24 21:35:32 +00:00
|
|
|
start_color: LegacyColor,
|
|
|
|
end_color: LegacyColor,
|
2023-03-20 20:57:54 +00:00
|
|
|
) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
self.line_gradient_2d(start, start + vector, start_color, end_color);
|
|
|
|
}
|
|
|
|
|
2023-07-31 19:14:52 +00:00
|
|
|
/// Draw a wireframe rectangle in 2D.
|
|
|
|
///
|
|
|
|
/// This should be called for each frame the rectangle needs to be rendered.
|
2023-03-28 20:58:02 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_gizmos::prelude::*;
|
|
|
|
/// # use bevy_render::prelude::*;
|
|
|
|
/// # use bevy_math::prelude::*;
|
|
|
|
/// fn system(mut gizmos: Gizmos) {
|
2024-02-24 21:35:32 +00:00
|
|
|
/// gizmos.rect_2d(Vec2::ZERO, 0., Vec2::ONE, LegacyColor::GREEN);
|
2023-03-28 20:58:02 +00:00
|
|
|
/// }
|
|
|
|
/// # bevy_ecs::system::assert_is_system(system);
|
|
|
|
/// ```
|
2023-03-20 20:57:54 +00:00
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
pub fn rect_2d(&mut self, position: Vec2, rotation: f32, size: Vec2, color: LegacyColor) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
let rotation = Mat2::from_angle(rotation);
|
|
|
|
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2);
|
|
|
|
self.linestrip_2d([tl, tr, br, bl, tl], color);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn extend_list_positions(&mut self, positions: impl IntoIterator<Item = Vec3>) {
|
2023-03-28 20:58:02 +00:00
|
|
|
self.buffer
|
|
|
|
.list_positions
|
2023-03-20 20:57:54 +00:00
|
|
|
.extend(positions.into_iter().map(|vec3| vec3.to_array()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
fn extend_list_colors(&mut self, colors: impl IntoIterator<Item = LegacyColor>) {
|
2023-03-28 20:58:02 +00:00
|
|
|
self.buffer
|
|
|
|
.list_colors
|
2024-02-26 23:50:33 +00:00
|
|
|
.extend(colors.into_iter().map(LinearRgba::from));
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2024-02-24 21:35:32 +00:00
|
|
|
fn add_list_color(&mut self, color: LegacyColor, count: usize) {
|
2023-03-28 20:58:02 +00:00
|
|
|
self.buffer
|
|
|
|
.list_colors
|
2024-02-26 23:50:33 +00:00
|
|
|
.extend(iter::repeat(LinearRgba::from(color)).take(count));
|
2023-03-20 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn extend_strip_positions(&mut self, positions: impl IntoIterator<Item = Vec3>) {
|
2023-03-28 20:58:02 +00:00
|
|
|
self.buffer.strip_positions.extend(
|
2023-03-20 20:57:54 +00:00
|
|
|
positions
|
|
|
|
.into_iter()
|
|
|
|
.map(|vec3| vec3.to_array())
|
|
|
|
.chain(iter::once([f32::NAN; 3])),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-28 20:58:02 +00:00
|
|
|
/// A builder returned by [`Gizmos::sphere`].
|
2024-01-18 15:52:50 +00:00
|
|
|
pub struct SphereBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
|
|
|
|
gizmos: &'a mut Gizmos<'w, 's, T>,
|
2023-03-20 20:57:54 +00:00
|
|
|
position: Vec3,
|
|
|
|
rotation: Quat,
|
|
|
|
radius: f32,
|
2024-02-24 21:35:32 +00:00
|
|
|
color: LegacyColor,
|
2023-03-20 20:57:54 +00:00
|
|
|
circle_segments: usize,
|
|
|
|
}
|
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
impl<T: GizmoConfigGroup> SphereBuilder<'_, '_, '_, T> {
|
2023-07-10 00:11:51 +00:00
|
|
|
/// Set the number of line-segments per circle for this sphere.
|
2023-03-20 20:57:54 +00:00
|
|
|
pub fn circle_segments(mut self, segments: usize) -> Self {
|
|
|
|
self.circle_segments = segments;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-18 15:52:50 +00:00
|
|
|
impl<T: GizmoConfigGroup> Drop for SphereBuilder<'_, '_, '_, T> {
|
2023-03-20 20:57:54 +00:00
|
|
|
fn drop(&mut self) {
|
2024-01-18 15:52:50 +00:00
|
|
|
if !self.gizmos.enabled {
|
|
|
|
return;
|
|
|
|
}
|
2023-03-20 20:57:54 +00:00
|
|
|
for axis in Vec3::AXES {
|
2023-03-28 20:58:02 +00:00
|
|
|
self.gizmos
|
2024-01-21 18:03:26 +00:00
|
|
|
.circle(
|
|
|
|
self.position,
|
Rename `Direction2d/3d` to `Dir2/3` (#12189)
# Objective
Split up from #12017, rename Bevy's direction types.
Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.
However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.
This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.
Some examples of what it looks like: (copied from #12017)
```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);
// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```
```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Direction3d::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
// After
let hit = spatial_query.cast_ray(
Vec3::ZERO,
Dir3::X,
f32::MAX,
true,
SpatialQueryFilter::default(),
);
```
```rust
// Before
self.circle(
Vec3::new(0.0, -2.0, 0.0),
Direction3d::Y,
5.0,
Color::TURQUOISE,
);
// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```
## Solution
Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.
---
## Migration Guide
The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.
## Additional Context
This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
|
|
|
Dir3::new_unchecked(self.rotation * axis),
|
2024-01-21 18:03:26 +00:00
|
|
|
self.radius,
|
|
|
|
self.color,
|
|
|
|
)
|
2023-03-20 20:57:54 +00:00
|
|
|
.segments(self.circle_segments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rect_inner(size: Vec2) -> [Vec2; 4] {
|
|
|
|
let half_size = size / 2.;
|
|
|
|
let tl = Vec2::new(-half_size.x, half_size.y);
|
|
|
|
let tr = Vec2::new(half_size.x, half_size.y);
|
|
|
|
let bl = Vec2::new(-half_size.x, -half_size.y);
|
|
|
|
let br = Vec2::new(half_size.x, -half_size.y);
|
|
|
|
[tl, tr, br, bl]
|
|
|
|
}
|