use crate::ui::Ui;
use crate::{Device, SAMPLE_COUNT};
use wgpu::util::DeviceExt;
pub mod rectangle;
pub mod circle;
pub mod image;
pub mod triangle;
pub trait WrcParam {
fn as_draw_param(&mut self, hovered: bool, mouse_down: bool) -> &[u8];
}
pub struct RenderParam<T> {
pub param: T,
buffer: Option<wgpu::Buffer>,
bind_group: Option<wgpu::BindGroup>,
}
impl<T: WrcParam> RenderParam<T> {
pub fn new(param: T) -> RenderParam<T> {
RenderParam {
param,
buffer: None,
bind_group: None,
}
}
pub fn update(&mut self, ui: &mut Ui, hovered: bool, pressed: bool) {
let data = self.param.as_draw_param(hovered, pressed);
ui.device.queue.write_buffer(self.buffer.as_ref().unwrap(), 0, data);
}
pub fn init_rectangle(&mut self, ui: &mut Ui, hovered: bool, pressed: bool) {
let data = self.param.as_draw_param(hovered, pressed);
let (buffer, bind_group) = ui.context.render.rectangle.init(&ui.device, data);
self.buffer = Some(buffer);
self.bind_group = Some(bind_group);
}
pub fn init_triangle(&mut self, ui: &mut Ui, hovered: bool, pressed: bool) {
let data = self.param.as_draw_param(hovered, pressed);
let (buffer, bind_group) = ui.context.render.triangle.init(&ui.device, data);
self.buffer = Some(buffer);
self.bind_group = Some(bind_group);
}
pub fn init_circle(&mut self, ui: &mut Ui, hovered: bool, pressed: bool) {
let data = self.param.as_draw_param(hovered, pressed);
let (buffer, bind_group) = ui.context.render.circle.init(&ui.device, data);
self.buffer = Some(buffer);
self.bind_group = Some(bind_group);
}
}
fn create_pipeline(device: &Device, shader: wgpu::ShaderModule, layout: wgpu::PipelineLayout, buffers: &[wgpu::VertexBufferLayout]) -> wgpu::RenderPipeline {
device.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers,
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format: device.texture_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: SAMPLE_COUNT,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
pub(crate) trait WrcRender {
fn pipeline(&self) -> &wgpu::RenderPipeline;
fn bind_group_layout(&self) -> &wgpu::BindGroupLayout;
fn init(&mut self, device: &Device, data: &[u8]) -> (wgpu::Buffer, wgpu::BindGroup) {
let buffer = device.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: data,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group_entry = wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
};
let bind_group = device.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: self.bind_group_layout(),
entries: &[bind_group_entry],
label: None,
});
(buffer, bind_group)
}
fn render<T>(&self, param: &RenderParam<T>, render_pass: &mut wgpu::RenderPass) {
render_pass.set_pipeline(self.pipeline());
render_pass.set_bind_group(0, param.bind_group.as_ref().unwrap(), &[]);
render_pass.draw(0..6, 0..1);
}
}