diff options
Diffstat (limited to 'client/src/renderer.rs')
-rw-r--r-- | client/src/renderer.rs | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/client/src/renderer.rs b/client/src/renderer.rs new file mode 100644 index 0000000..b21c139 --- /dev/null +++ b/client/src/renderer.rs @@ -0,0 +1,158 @@ +use anyhow::{Result, anyhow}; +use pollster::FutureExt; +use wgpu::{ + Backends, BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color, + ColorTargetState, ColorWrites, CommandEncoderDescriptor, Device, DeviceDescriptor, Features, + FragmentState, FrontFace, Instance, InstanceDescriptor, Limits, LoadOp, MaintainBase, + MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor, + PolygonMode, PowerPreference, PrimitiveState, PrimitiveTopology, Queue, + RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, + RequestAdapterOptions, StoreOp, Surface, SurfaceConfiguration, TextureViewDescriptor, + VertexState, include_wgsl, +}; +use winit::window::Window; + +pub struct Renderer<'a> { + surface: Surface<'a>, + pipeline: RenderPipeline, + bind_group: BindGroup, + queue: Queue, + device: Device, + surface_configuration: SurfaceConfiguration, +} +impl<'a> Renderer<'a> { + pub fn new(window: &'a Window) -> Result<Self> { + let instance = Instance::new(InstanceDescriptor { + backends: Backends::all(), + ..Default::default() + }); + + let surface = instance.create_surface(window)?; + let adapter = instance + .request_adapter(&RequestAdapterOptions { + compatible_surface: Some(&surface), + power_preference: PowerPreference::HighPerformance, + ..Default::default() + }) + .block_on() + .ok_or(anyhow!("no adapter found"))?; + + let (device, queue) = adapter + .request_device( + &DeviceDescriptor { + required_features: Features::default(), + required_limits: Limits::downlevel_defaults(), + ..Default::default() + }, + None, + ) + .block_on()?; + + let surface_configuration = surface + .get_default_config(&adapter, 256, 256) + .ok_or(anyhow!("no default config"))?; + + let module = device.create_shader_module(include_wgsl!("shader.wgsl")); + + let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[], + label: None, + }); + let bind_group = device.create_bind_group(&BindGroupDescriptor { + label: None, + layout: &bind_group_layout, + entries: &[], + }); + let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }); + let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + fragment: Some(FragmentState { + module: &module, + entry_point: Some("fs_main"), + targets: &[Some(ColorTargetState { + blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING), + format: surface_configuration.format, + write_mask: ColorWrites::all(), + })], + compilation_options: PipelineCompilationOptions::default(), + }), + vertex: VertexState { + module: &module, + entry_point: Some("vs_main"), + buffers: &[], + compilation_options: PipelineCompilationOptions::default(), + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + front_face: FrontFace::Ccw, + cull_mode: None, //Some(Face::Back), + polygon_mode: PolygonMode::Fill, + ..Default::default() + }, + depth_stencil: Default::default(), + multisample: MultisampleState::default(), + multiview: None, + cache: None, + }); + + surface.configure(&device, &surface_configuration); + + Ok(Self { + surface, + pipeline, + bind_group, + device, + queue, + surface_configuration, + }) + } + + pub fn resize(&mut self, width: u32, height: u32) { + self.surface_configuration.width = width; + self.surface_configuration.height = height; + self.surface + .configure(&self.device, &self.surface_configuration); + } + + pub fn draw(&mut self) -> Result<()> { + let target = self.surface.get_current_texture()?; + let target_view = target + .texture + .create_view(&TextureViewDescriptor::default()); + + let mut commands = self + .device + .create_command_encoder(&CommandEncoderDescriptor { label: None }); + + { + let mut rpass = commands.begin_render_pass(&RenderPassDescriptor { + label: None, + color_attachments: &[Some(RenderPassColorAttachment { + view: &target_view, + resolve_target: None, + ops: Operations { + store: StoreOp::Store, + load: LoadOp::Clear(Color::BLUE), + }, + })], + ..Default::default() + }); + + rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.set_pipeline(&self.pipeline); + rpass.draw(0..3, 0..1); + } + + let i = self.queue.submit(Some(commands.finish())); + self.device.poll(MaintainBase::WaitForSubmissionIndex(i)); + + target.present(); + + Ok(()) + } +} |