From abc6f983cebd90ebf47eb93a02aa4a57cb5387fc Mon Sep 17 00:00:00 2001 From: IceSentry Date: Mon, 26 Feb 2024 17:31:49 -0500 Subject: [PATCH] Impl ShaderType for LinearRgba (#12137) # Objective - LinearRgba is the color type intended for shaders but using it for shaders is currently not easy because it doesn't implement ShaderType ## Solution - add encase as a dependency and impl the required traits. --------- Co-authored-by: Alice Cecile Co-authored-by: Zachary Harrold --- crates/bevy_color/Cargo.toml | 1 + crates/bevy_color/src/linear_rgba.rs | 71 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml index 4997436e19..fa88cc611d 100644 --- a/crates/bevy_color/Cargo.toml +++ b/crates/bevy_color/Cargo.toml @@ -16,6 +16,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev", features = [ serde = "1.0" thiserror = "1.0" wgpu = { version = "0.19.1", default-features = false } +encase = { version = "0.7", default-features = false } [lints] workspace = true diff --git a/crates/bevy_color/src/linear_rgba.rs b/crates/bevy_color/src/linear_rgba.rs index 9a682b2ac9..85b3c2f094 100644 --- a/crates/bevy_color/src/linear_rgba.rs +++ b/crates/bevy_color/src/linear_rgba.rs @@ -210,6 +210,77 @@ impl From for wgpu::Color { } } +// [`LinearRgba`] is intended to be used with shaders +// So it's the only color type that implements [`ShaderType`] to make it easier to use inside shaders +impl encase::ShaderType for LinearRgba { + type ExtraMetadata = (); + + const METADATA: encase::private::Metadata = { + let size = + encase::private::SizeValue::from(::SHADER_SIZE) + .mul(4); + let alignment = encase::private::AlignmentValue::from_next_power_of_two_size(size); + + encase::private::Metadata { + alignment, + has_uniform_min_alignment: false, + min_size: size, + extra: (), + } + }; + + const UNIFORM_COMPAT_ASSERT: fn() = || {}; +} + +impl encase::private::WriteInto for LinearRgba { + fn write_into(&self, writer: &mut encase::private::Writer) { + for el in &[self.red, self.green, self.blue, self.alpha] { + encase::private::WriteInto::write_into(el, writer); + } + } +} + +impl encase::private::ReadFrom for LinearRgba { + fn read_from( + &mut self, + reader: &mut encase::private::Reader, + ) { + let mut buffer = [0.0f32; 4]; + for el in &mut buffer { + encase::private::ReadFrom::read_from(el, reader); + } + + *self = LinearRgba { + red: buffer[0], + green: buffer[1], + blue: buffer[2], + alpha: buffer[3], + } + } +} + +impl encase::private::CreateFrom for LinearRgba { + fn create_from(reader: &mut encase::private::Reader) -> Self + where + B: encase::private::BufferRef, + { + // These are intentionally not inlined in the constructor to make this + // resilient to internal Color refactors / implicit type changes. + let red: f32 = encase::private::CreateFrom::create_from(reader); + let green: f32 = encase::private::CreateFrom::create_from(reader); + let blue: f32 = encase::private::CreateFrom::create_from(reader); + let alpha: f32 = encase::private::CreateFrom::create_from(reader); + LinearRgba { + red, + green, + blue, + alpha, + } + } +} + +impl encase::ShaderSize for LinearRgba {} + #[cfg(test)] mod tests { use super::*;