diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml index fa88cc611d726..e23bdddc48817 100644 --- a/crates/bevy_color/Cargo.toml +++ b/crates/bevy_color/Cargo.toml @@ -13,6 +13,7 @@ bevy_math = { path = "../bevy_math", version = "0.14.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [ "bevy", ] } +bytemuck = "1" serde = "1.0" thiserror = "1.0" wgpu = { version = "0.19.1", default-features = false } diff --git a/crates/bevy_color/src/linear_rgba.rs b/crates/bevy_color/src/linear_rgba.rs index 85b3c2f094aba..462c7033e60a6 100644 --- a/crates/bevy_color/src/linear_rgba.rs +++ b/crates/bevy_color/src/linear_rgba.rs @@ -1,11 +1,13 @@ use crate::{color_difference::EuclideanDistance, Alpha, Luminance, Mix, StandardColor}; use bevy_math::Vec4; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +use bytemuck::{Pod, Zeroable}; use serde::{Deserialize, Serialize}; /// Linear RGB color with alpha. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Reflect)] #[reflect(PartialEq, Serialize, Deserialize)] +#[repr(C)] pub struct LinearRgba { /// The red channel. [0.0, 1.0] pub red: f32, @@ -44,6 +46,18 @@ impl LinearRgba { alpha: 0.0, }; + /// An invalid color. + /// + /// This type can be used to represent an invalid color value; + /// in some rendering applications the color will be ignored, + /// enabling performant hacks like hiding lines by setting their color to `INVALID`. + pub const NAN: Self = Self { + red: f32::NAN, + green: f32::NAN, + blue: f32::NAN, + alpha: f32::NAN, + }; + /// Construct a new [`LinearRgba`] color from components. pub const fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self { Self { @@ -279,6 +293,33 @@ impl encase::private::CreateFrom for LinearRgba { } } +/// A [`Zeroable`] type is one whose bytes can be filled with zeroes while remaining valid. +/// +/// SAFETY: [`LinearRgba`] is inhabited +/// SAFETY: [`LinearRgba`]'s all-zero bit pattern is a valid value +unsafe impl Zeroable for LinearRgba { + fn zeroed() -> Self { + LinearRgba { + red: 0.0, + green: 0.0, + blue: 0.0, + alpha: 0.0, + } + } +} + +/// The [`Pod`] trait is [`bytemuck`]'s marker for types that can be safely transmuted from a byte array. +/// +/// It is intended to only be implemented for types which are "Plain Old Data". +/// +/// SAFETY: [`LinearRgba`] is inhabited. +/// SAFETY: [`LinearRgba`] permits any bit value. +/// SAFETY: [`LinearRgba`] does not have padding bytes. +/// SAFETY: all of the fields of [`LinearRgba`] are [`Pod`], as f32 is [`Pod`]. +/// SAFETY: [`LinearRgba`] is `repr(C)` +/// SAFETY: [`LinearRgba`] does not permit interior mutability. +unsafe impl Pod for LinearRgba {} + impl encase::ShaderSize for LinearRgba {} #[cfg(test)] diff --git a/crates/bevy_gizmos/Cargo.toml b/crates/bevy_gizmos/Cargo.toml index 387df207b500a..b573c5d6d921d 100644 --- a/crates/bevy_gizmos/Cargo.toml +++ b/crates/bevy_gizmos/Cargo.toml @@ -17,6 +17,7 @@ webgpu = [] bevy_pbr = { path = "../bevy_pbr", version = "0.14.0-dev", optional = true } bevy_sprite = { path = "../bevy_sprite", version = "0.14.0-dev", optional = true } bevy_app = { path = "../bevy_app", version = "0.14.0-dev" } +bevy_color = { path = "../bevy_color", version = "0.14.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" } bevy_math = { path = "../bevy_math", version = "0.14.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.14.0-dev" } diff --git a/crates/bevy_gizmos/src/gizmos.rs b/crates/bevy_gizmos/src/gizmos.rs index 011477fe6694a..adb18fff5cc4f 100644 --- a/crates/bevy_gizmos/src/gizmos.rs +++ b/crates/bevy_gizmos/src/gizmos.rs @@ -3,6 +3,7 @@ use std::{iter, marker::PhantomData}; use crate::circles::DEFAULT_CIRCLE_SEGMENTS; +use bevy_color::LinearRgba; use bevy_ecs::{ component::Tick, system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam}, @@ -19,14 +20,13 @@ use crate::{ }; type PositionItem = [f32; 3]; -type ColorItem = [f32; 4]; #[derive(Resource, Default)] pub(crate) struct GizmoStorage { - pub list_positions: Vec, - pub list_colors: Vec, - pub strip_positions: Vec, - pub strip_colors: Vec, + pub(crate) list_positions: Vec, + pub(crate) list_colors: Vec, + pub(crate) strip_positions: Vec, + pub(crate) strip_colors: Vec, marker: PhantomData, } @@ -104,9 +104,9 @@ where #[derive(Default)] struct GizmoBuffer { list_positions: Vec, - list_colors: Vec, + list_colors: Vec, strip_positions: Vec, - strip_colors: Vec, + strip_colors: Vec, marker: PhantomData, } @@ -244,10 +244,8 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { } self.extend_strip_positions(positions); let len = self.buffer.strip_positions.len(); - self.buffer - .strip_colors - .resize(len - 1, color.as_linear_rgba_f32()); - self.buffer.strip_colors.push([f32::NAN; 4]); + self.buffer.strip_colors.resize(len - 1, color.into()); + self.buffer.strip_colors.push(LinearRgba::NAN); } /// Draw a line in 3D made of straight segments between the points, with a color gradient. @@ -287,11 +285,11 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { for (position, color) in points { strip_positions.push(position.to_array()); - strip_colors.push(color.as_linear_rgba_f32()); + strip_colors.push(color.into()); } strip_positions.push([f32::NAN; 3]); - strip_colors.push([f32::NAN; 4]); + strip_colors.push(LinearRgba::NAN); } /// Draw a wireframe sphere in 3D made out of 3 circles around the axes. @@ -583,14 +581,14 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { fn extend_list_colors(&mut self, colors: impl IntoIterator) { self.buffer .list_colors - .extend(colors.into_iter().map(|color| color.as_linear_rgba_f32())); + .extend(colors.into_iter().map(LinearRgba::from)); } #[inline] fn add_list_color(&mut self, color: LegacyColor, count: usize) { self.buffer .list_colors - .extend(iter::repeat(color.as_linear_rgba_f32()).take(count)); + .extend(iter::repeat(LinearRgba::from(color)).take(count)); } #[inline] diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 18db82467efee..1dd86c5ac577f 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -52,6 +52,7 @@ pub mod prelude { use aabb::AabbGizmoPlugin; use bevy_app::{App, Last, Plugin}; use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle}; +use bevy_color::LinearRgba; use bevy_core::cast_slice; use bevy_ecs::{ component::Component, @@ -309,7 +310,7 @@ struct LineGizmoUniform { #[derive(Asset, Debug, Default, Clone, TypePath)] struct LineGizmo { positions: Vec<[f32; 3]>, - colors: Vec<[f32; 4]>, + colors: Vec, /// Whether this gizmo's topology is a line-strip or line-list strip: bool, }