wgpu_3dgs_editor/buffer/
modifier.rs

1use glam::*;
2use wgpu::util::DeviceExt;
3
4use crate::core::{self, BufferWrapper, FixedSizeBufferWrapper};
5
6/// The basic color modifiers buffer for the [`BasicModifierBundle`](crate::BasicModifierBundle).
7///
8/// This buffer holds the data for basic color modifications, including RGB override or
9/// HSV modifications, alpha, contrast, exposure, and gamma adjustments.
10#[derive(Debug, Clone)]
11pub struct BasicColorModifiersBuffer(wgpu::Buffer);
12
13impl BasicColorModifiersBuffer {
14    /// Create a new basic color modifiers buffer.
15    pub fn new(device: &wgpu::Device) -> Self {
16        let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
17            label: Some("Basic Color Modifiers Buffer"),
18            contents: bytemuck::bytes_of(&BasicColorModifiersPod::default()),
19            usage: Self::DEFAULT_USAGES,
20        });
21
22        Self(buffer)
23    }
24
25    /// Update the basic color modifiers.
26    pub fn update(
27        &self,
28        queue: &wgpu::Queue,
29        rgb_or_hsv: BasicColorRgbOverrideOrHsvModifiersPod,
30        alpha: f32,
31        contrast: f32,
32        exposure: f32,
33        gamma: f32,
34    ) {
35        self.update_with_pod(
36            queue,
37            &BasicColorModifiersPod::new(rgb_or_hsv, alpha, contrast, exposure, gamma),
38        );
39    }
40
41    /// Update the basic color modifiers buffer with [`BasicColorModifiersPod`].
42    pub fn update_with_pod(&self, queue: &wgpu::Queue, pod: &BasicColorModifiersPod) {
43        queue.write_buffer(&self.0, 0, bytemuck::bytes_of(pod));
44    }
45}
46
47impl BufferWrapper for BasicColorModifiersBuffer {
48    fn buffer(&self) -> &wgpu::Buffer {
49        &self.0
50    }
51}
52
53impl From<BasicColorModifiersBuffer> for wgpu::Buffer {
54    fn from(wrapper: BasicColorModifiersBuffer) -> Self {
55        wrapper.0
56    }
57}
58
59impl TryFrom<wgpu::Buffer> for BasicColorModifiersBuffer {
60    type Error = core::FixedSizeBufferWrapperError;
61
62    fn try_from(buffer: wgpu::Buffer) -> Result<Self, Self::Error> {
63        Self::verify_buffer_size(&buffer).map(|()| Self(buffer))
64    }
65}
66
67impl FixedSizeBufferWrapper for BasicColorModifiersBuffer {
68    type Pod = BasicColorModifiersPod;
69}
70
71/// The POD representation of the basic color RGB override or HSV modifiers.
72///
73/// If any value of this vector is negative (including negative zero),
74/// then it is used to override the RGB color,
75/// otherwise it is used to apply HSV modifications.
76#[repr(transparent)]
77#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
78pub struct BasicColorRgbOverrideOrHsvModifiersPod(pub Vec3);
79
80impl BasicColorRgbOverrideOrHsvModifiersPod {
81    /// Creates a new RGB override pod.
82    pub fn new_rgb_override(rgb: Vec3) -> Self {
83        Self(-rgb)
84    }
85
86    /// Creates a new HSV modifiers pod.
87    pub const fn new_hsv_modifiers(hsv: Vec3) -> Self {
88        Self(hsv)
89    }
90
91    /// Checks if this pod represents an RGB override.
92    pub fn is_rgb_override(&self) -> bool {
93        self.0.x.is_sign_negative() || self.0.y.is_sign_negative() || self.0.z.is_sign_negative()
94    }
95
96    /// Checks if this pod represents HSV modifiers.
97    pub fn is_hsv_modifiers(&self) -> bool {
98        !self.is_rgb_override()
99    }
100
101    /// Returns the [`Vec3`] value, negating it if this represents an RGB override.
102    pub fn get_vec3(&self) -> Vec3 {
103        if self.is_rgb_override() {
104            -self.0
105        } else {
106            self.0
107        }
108    }
109}
110
111/// The POD representation of the basic color modifiers buffer.
112#[repr(C)]
113#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
114pub struct BasicColorModifiersPod {
115    pub rgb_or_hsv: BasicColorRgbOverrideOrHsvModifiersPod,
116    pub alpha: f32,
117    pub contrast: f32,
118    pub exposure: f32,
119    pub gamma: f32,
120    pub _padding: u32,
121}
122
123impl BasicColorModifiersPod {
124    /// Create a new basic color modifiers pod.
125    pub fn new(
126        rgb_or_hsv: BasicColorRgbOverrideOrHsvModifiersPod,
127        alpha: f32,
128        contrast: f32,
129        exposure: f32,
130        gamma: f32,
131    ) -> Self {
132        Self {
133            rgb_or_hsv,
134            alpha,
135            contrast,
136            exposure,
137            gamma,
138            _padding: 0,
139        }
140    }
141}
142
143impl Default for BasicColorModifiersPod {
144    fn default() -> Self {
145        Self {
146            rgb_or_hsv: BasicColorRgbOverrideOrHsvModifiersPod::new_hsv_modifiers(Vec3::new(
147                0.0, 1.0, 1.0,
148            )),
149            alpha: 1.0,
150            contrast: 0.0,
151            exposure: 0.0,
152            gamma: 1.0,
153            _padding: 0,
154        }
155    }
156}
157
158/// The transform flags buffer for the [`BasicModifierBundle`](crate::BasicModifierBundle).
159#[derive(Debug, Clone)]
160pub struct TransformFlagsBuffer(wgpu::Buffer);
161
162impl TransformFlagsBuffer {
163    /// Create a new transform flags buffer.
164    pub fn new(device: &wgpu::Device) -> Self {
165        let buffer = device.create_buffer(&wgpu::BufferDescriptor {
166            label: Some("Transform Flags Buffer"),
167            size: std::mem::size_of::<u32>() as wgpu::BufferAddress,
168            usage: Self::DEFAULT_USAGES,
169            mapped_at_creation: false,
170        });
171
172        Self(buffer)
173    }
174
175    /// Update the transform flags buffer.
176    pub fn update(&self, queue: &wgpu::Queue, flags: TransformFlags) {
177        queue.write_buffer(&self.0, 0, bytemuck::bytes_of(&flags.bits()));
178    }
179}
180
181impl BufferWrapper for TransformFlagsBuffer {
182    fn buffer(&self) -> &wgpu::Buffer {
183        &self.0
184    }
185}
186
187impl From<TransformFlagsBuffer> for wgpu::Buffer {
188    fn from(wrapper: TransformFlagsBuffer) -> Self {
189        wrapper.0
190    }
191}
192
193impl TryFrom<wgpu::Buffer> for TransformFlagsBuffer {
194    type Error = core::FixedSizeBufferWrapperError;
195
196    fn try_from(buffer: wgpu::Buffer) -> Result<Self, Self::Error> {
197        Self::verify_buffer_size(&buffer).map(|()| Self(buffer))
198    }
199}
200
201impl FixedSizeBufferWrapper for TransformFlagsBuffer {
202    type Pod = u32;
203}
204
205bitflags::bitflags! {
206    /// Flags for whether to apply model and Gaussian transforms.
207    #[repr(transparent)]
208    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
209    pub struct TransformFlags: u32 {
210        /// Whether to apply the model transform.
211        const MODEL = 0b0001;
212        /// Whether to apply the Gaussian transform.
213        const GAUSSIAN = 0b0010;
214    }
215}
216
217/// The scale rotation buffer for the [`BasicModifierBundle`](crate::BasicModifierBundle).
218///
219/// This buffer holds the per Gaussian rotation and scale modification data.
220#[derive(Debug, Clone)]
221pub struct RotScaleBuffer(wgpu::Buffer);
222
223impl RotScaleBuffer {
224    /// Create a new scale and rotation buffer.
225    pub fn new(device: &wgpu::Device) -> Self {
226        let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
227            label: Some("Scale Rot Buffer"),
228            contents: bytemuck::bytes_of(&RotScalePod::default()),
229            usage: Self::DEFAULT_USAGES,
230        });
231
232        Self(buffer)
233    }
234
235    /// Update the scale and rotation buffer.
236    pub fn update(&self, queue: &wgpu::Queue, rot: Quat, scale: Vec3) {
237        self.update_with_pod(queue, &RotScalePod::new(rot, scale));
238    }
239
240    /// Update the scale and rotation buffer with [`RotScalePod`].
241    pub fn update_with_pod(&self, queue: &wgpu::Queue, pod: &RotScalePod) {
242        queue.write_buffer(&self.0, 0, bytemuck::bytes_of(pod));
243    }
244}
245
246impl BufferWrapper for RotScaleBuffer {
247    fn buffer(&self) -> &wgpu::Buffer {
248        &self.0
249    }
250}
251
252impl From<RotScaleBuffer> for wgpu::Buffer {
253    fn from(wrapper: RotScaleBuffer) -> Self {
254        wrapper.0
255    }
256}
257
258impl TryFrom<wgpu::Buffer> for RotScaleBuffer {
259    type Error = core::FixedSizeBufferWrapperError;
260
261    fn try_from(buffer: wgpu::Buffer) -> Result<Self, Self::Error> {
262        Self::verify_buffer_size(&buffer).map(|()| Self(buffer))
263    }
264}
265
266impl FixedSizeBufferWrapper for RotScaleBuffer {
267    type Pod = RotScalePod;
268}
269
270/// The POD representation of the scale and rotation buffer.
271#[repr(C)]
272#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
273pub struct RotScalePod {
274    pub rot: Quat,
275    pub scale: Vec3A,
276}
277
278impl RotScalePod {
279    /// Create a new scale and rotation pod.
280    pub const fn new(rot: Quat, scale: Vec3) -> Self {
281        Self {
282            rot,
283            scale: Vec3A::from_array(scale.to_array()),
284        }
285    }
286}
287
288impl Default for RotScalePod {
289    fn default() -> Self {
290        Self {
291            rot: Quat::IDENTITY,
292            scale: Vec3A::ONE,
293        }
294    }
295}