wgpu_3dgs_editor/buffer/
selection.rs

1use glam::*;
2use wgpu::util::DeviceExt;
3
4use crate::core::{self, BufferWrapper, FixedSizeBufferWrapper};
5
6/// The selection storage buffer.
7///
8/// This buffer holds the selection bitmask for Gaussians, where each bit represents whether
9/// a Gaussian is selected (1) or not (0).
10#[derive(Debug, Clone)]
11pub struct SelectionBuffer(wgpu::Buffer);
12
13impl SelectionBuffer {
14    /// Create a new selection buffer.
15    pub fn new(device: &wgpu::Device, gaussian_count: u32) -> Self {
16        Self::new_with_label(device, "", gaussian_count)
17    }
18
19    /// Create a new selection buffer with additional label.
20    pub fn new_with_label(device: &wgpu::Device, label: &str, gaussian_count: u32) -> Self {
21        let size = gaussian_count.div_ceil(32) * std::mem::size_of::<u32>() as u32;
22
23        let data = device.create_buffer(&wgpu::BufferDescriptor {
24            label: Some(format!("{label} Selection Buffer").as_str()),
25            size: size as wgpu::BufferAddress,
26            usage: Self::DEFAULT_USAGES,
27            mapped_at_creation: false,
28        });
29
30        Self(data)
31    }
32}
33
34impl BufferWrapper for SelectionBuffer {
35    const DEFAULT_USAGES: wgpu::BufferUsages = wgpu::BufferUsages::from_bits_retain(
36        wgpu::BufferUsages::STORAGE.bits()
37            | wgpu::BufferUsages::COPY_DST.bits()
38            | wgpu::BufferUsages::COPY_SRC.bits(),
39    );
40
41    fn buffer(&self) -> &wgpu::Buffer {
42        &self.0
43    }
44}
45
46impl From<SelectionBuffer> for wgpu::Buffer {
47    fn from(wrapper: SelectionBuffer) -> Self {
48        wrapper.0
49    }
50}
51
52impl From<wgpu::Buffer> for SelectionBuffer {
53    fn from(buffer: wgpu::Buffer) -> Self {
54        Self(buffer)
55    }
56}
57
58/// The selection operation uniform buffer for storing selection operations.
59///
60/// This buffer holds a single u32 value representing the index of the selection operation to be
61/// performed, this includes both primitive operations and custom operations, the value is obtained
62/// from [`SelectionExpr::as_u32`](crate::SelectionExpr::as_u32), see its documentation for more
63/// details.
64#[derive(Debug, Clone)]
65pub struct SelectionOpBuffer(wgpu::Buffer);
66
67impl SelectionOpBuffer {
68    /// Create a new selection operation buffer.
69    pub fn new(device: &wgpu::Device, op: u32) -> Self {
70        let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
71            label: Some("Selection Operation Buffer"),
72            contents: bytemuck::bytes_of(&op),
73            usage: Self::DEFAULT_USAGES,
74        });
75
76        Self(buffer)
77    }
78
79    /// Update the selection operation buffer.
80    pub fn update(&self, queue: &wgpu::Queue, op: u32) {
81        queue.write_buffer(&self.0, 0, bytemuck::bytes_of(&op));
82    }
83}
84
85impl BufferWrapper for SelectionOpBuffer {
86    fn buffer(&self) -> &wgpu::Buffer {
87        &self.0
88    }
89}
90
91impl From<SelectionOpBuffer> for wgpu::Buffer {
92    fn from(wrapper: SelectionOpBuffer) -> Self {
93        wrapper.0
94    }
95}
96
97impl TryFrom<wgpu::Buffer> for SelectionOpBuffer {
98    type Error = core::FixedSizeBufferWrapperError;
99
100    fn try_from(buffer: wgpu::Buffer) -> Result<Self, Self::Error> {
101        Self::verify_buffer_size(&buffer).map(|()| Self(buffer))
102    }
103}
104
105impl FixedSizeBufferWrapper for SelectionOpBuffer {
106    type Pod = u32;
107}
108
109/// An inverse transform uniform buffer for selection operations.
110///
111/// This buffer holds the inverse of the combined scale, rotation, and translation transform,
112/// which is used for [`SelectionBundle::create_sphere_bundle`](crate::SelectionBundle::create_sphere_bundle)
113/// and [`SelectionBundle::create_box_bundle`](crate::SelectionBundle::create_box_bundle), but
114/// can also be used for your custom selection operations.
115#[derive(Debug, Clone)]
116pub struct InvTransformBuffer(wgpu::Buffer);
117
118impl InvTransformBuffer {
119    /// Create a new inverse transform buffer.
120    pub fn new(device: &wgpu::Device) -> Self {
121        let buffer = device.create_buffer(&wgpu::BufferDescriptor {
122            label: Some("Inverse Transform Buffer"),
123            size: std::mem::size_of::<Mat4>() as wgpu::BufferAddress,
124            usage: Self::DEFAULT_USAGES,
125            mapped_at_creation: false,
126        });
127
128        Self(buffer)
129    }
130
131    /// Update the inverse transform buffer.
132    pub fn update(&self, queue: &wgpu::Queue, inv_transform: Mat4) {
133        queue.write_buffer(&self.0, 0, bytemuck::bytes_of(&inv_transform));
134    }
135
136    /// Update the sphere selection buffer with the scale, rotation, and position.
137    pub fn update_with_scale_rot_pos(
138        &self,
139        queue: &wgpu::Queue,
140        scale: Vec3,
141        rot: Quat,
142        pos: Vec3,
143    ) {
144        let inv_transform = Mat4::from_scale_rotation_translation(scale, rot, pos).inverse();
145        self.update(queue, inv_transform);
146    }
147}
148
149impl BufferWrapper for InvTransformBuffer {
150    fn buffer(&self) -> &wgpu::Buffer {
151        &self.0
152    }
153}
154
155impl From<InvTransformBuffer> for wgpu::Buffer {
156    fn from(wrapper: InvTransformBuffer) -> Self {
157        wrapper.0
158    }
159}
160
161impl TryFrom<wgpu::Buffer> for InvTransformBuffer {
162    type Error = core::FixedSizeBufferWrapperError;
163
164    fn try_from(buffer: wgpu::Buffer) -> Result<Self, Self::Error> {
165        Self::verify_buffer_size(&buffer).map(|()| Self(buffer))
166    }
167}
168
169impl FixedSizeBufferWrapper for InvTransformBuffer {
170    type Pod = Mat4;
171}