use glam::*;
use crate::{
CameraBuffer, RendererCreateError,
selection::{
ViewportTexture, ViewportTextureBrushRenderer, ViewportTextureF32Buffer,
ViewportTexturePosBuffer, ViewportTextureRectangleRenderer,
},
};
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ViewportSelectorType {
#[default]
Rectangle,
Brush,
}
#[derive(Debug)]
pub struct ViewportSelector {
start_pos: Option<Vec2>,
end_pos: Option<Vec2>,
brush_radius: f32,
start_buffer: ViewportTexturePosBuffer,
end_buffer: ViewportTexturePosBuffer,
radius_buffer: ViewportTextureF32Buffer,
viewport_texture: ViewportTexture,
rectangle_renderer: ViewportTextureRectangleRenderer,
brush_renderer: ViewportTextureBrushRenderer,
pub selector_type: ViewportSelectorType,
}
impl ViewportSelector {
pub const DEFAULT_BRUSH_RADIUS: f32 = 50.0;
pub fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
viewport_size: UVec2,
camera: &CameraBuffer,
) -> Result<Self, RendererCreateError> {
let start_buffer = ViewportTexturePosBuffer::new(device);
let end_buffer = ViewportTexturePosBuffer::new(device);
let radius_buffer = ViewportTextureF32Buffer::new(device);
radius_buffer.update(queue, Self::DEFAULT_BRUSH_RADIUS);
let viewport_texture = ViewportTexture::new(device, viewport_size);
let rectangle_renderer = ViewportTextureRectangleRenderer::new(
device,
&viewport_texture,
camera,
&start_buffer,
&end_buffer,
)?;
let brush_renderer = ViewportTextureBrushRenderer::new(
device,
&viewport_texture,
camera,
&start_buffer,
&end_buffer,
&radius_buffer,
)?;
Ok(Self {
start_pos: None,
end_pos: None,
brush_radius: Self::DEFAULT_BRUSH_RADIUS,
start_buffer,
end_buffer,
radius_buffer,
viewport_texture,
rectangle_renderer,
brush_renderer,
selector_type: ViewportSelectorType::default(),
})
}
pub fn start(&mut self, queue: &wgpu::Queue, pos: Vec2) {
self.start_pos = Some(pos);
self.start_buffer.update(queue, pos);
self.end_pos = Some(pos);
self.end_buffer.update(queue, pos);
}
pub fn update(&mut self, queue: &wgpu::Queue, pos: Vec2) {
match self.selector_type {
ViewportSelectorType::Rectangle => {
self.end_pos = Some(pos);
self.end_buffer.update(queue, pos);
}
ViewportSelectorType::Brush => {
self.start_pos = self.end_pos;
self.start_buffer
.update(queue, self.start_pos.unwrap_or(pos));
self.end_pos = Some(pos);
self.end_buffer.update(queue, pos);
}
}
}
pub fn clear(&mut self, encoder: &mut wgpu::CommandEncoder) {
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Viewport Selection Clear Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: self.viewport_texture.view(),
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
..Default::default()
});
}
pub fn render(&self, encoder: &mut wgpu::CommandEncoder) {
match self.selector_type {
ViewportSelectorType::Rectangle => self
.rectangle_renderer
.render(encoder, &self.viewport_texture),
ViewportSelectorType::Brush => {
self.brush_renderer.render(encoder, &self.viewport_texture)
}
}
}
pub fn texture(&self) -> &ViewportTexture {
&self.viewport_texture
}
pub fn set_brush_radius(&mut self, queue: &wgpu::Queue, radius: f32) {
self.brush_radius = radius;
self.radius_buffer.update(queue, radius);
}
pub fn resize(&mut self, device: &wgpu::Device, new_size: UVec2) {
self.viewport_texture = ViewportTexture::new(device, new_size);
}
}