pteropus/src/app/mod.rs

206 lines
6.6 KiB
Rust

use std::rc::Rc;
use crate::mvu::{Event, MvuApp, Size2i};
use {
log::info,
std::{borrow::Cow, path::PathBuf},
wgpu::{Device, Instance, Queue, RenderPipeline, Surface, SurfaceConfiguration},
};
mod dem_renderer;
mod raster;
use dem_renderer::DemRenderer;
#[derive(Clone)]
pub struct Model {
dem: Option<Rc<raster::Dem>>,
}
impl Model {
pub fn new() -> Model {
Model { dem: None }
}
}
struct Context {
config: SurfaceConfiguration,
surface: Surface<'static>,
device: Device,
render_pipeline: RenderPipeline,
queue: Queue,
scene_data: Option<DemRenderer>,
}
#[derive(Default)]
pub struct App {
context: Option<Context>,
}
impl App {
pub fn new() -> Self {
Self::default()
}
}
impl MvuApp<Model> for App {
async fn init(&mut self, instance: &Instance, surface: Surface<'static>, size: Size2i) {
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: Some(&surface),
})
.await
.expect("Failed to find an appropriate adapter");
eprintln!("Using {}", adapter.get_info().name);
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
.using_resolution(adapter.limits()),
memory_hints: wgpu::MemoryHints::MemoryUsage,
},
None,
)
.await
.expect("Failed to create device");
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let swapchain_capabilities = surface.get_capabilities(&adapter);
let swapchain_format = swapchain_capabilities.formats[0];
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(swapchain_format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
});
let mut config = surface
.get_default_config(&adapter, size.width, size.height)
.unwrap();
config.present_mode = wgpu::PresentMode::AutoVsync;
config.view_formats.push(config.format);
surface.configure(&device, &config);
self.context = Some(Context {
config,
surface,
device,
render_pipeline,
queue,
scene_data: None,
});
info!("Initialized {}x{}.", size.width, size.height);
}
async fn resize(&mut self, new_size: Size2i) {
if let Some(Context {
config,
surface,
device,
..
}) = &mut self.context
{
config.width = new_size.width.max(1);
config.height = new_size.height.max(1);
surface.configure(device, config);
info!("Resized_to {}x{}.", new_size.width, new_size.height);
}
}
async fn update(&self, model: Rc<Model>, event: Event) -> Rc<Model> {
match event {
Event::MouseButtonPressed => model,
Event::OpenTestFile(file_path) => open_test_file(file_path, model.clone()),
}
}
async fn view(&mut self, model: Rc<Model>) -> Result<(), Box<dyn std::error::Error>> {
if let Some(context) = &mut self.context {
if context.scene_data.is_none() {
if let Some(dem) = &model.dem {
context.scene_data = Some(DemRenderer::new(
dem.clone(),
&context.device,
&context.config,
&context.queue,
))
}
}
let frame = context
.surface
.get_current_texture()
.expect("Failed to acquire next swap chain texture");
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
if let Some(scene_data) = &mut context.scene_data {
scene_data.render(&view, &context.device, &context.queue);
} else {
let mut encoder = context
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
rpass.set_pipeline(&context.render_pipeline);
rpass.draw(0..3, 0..1);
}
context.queue.submit(Some(encoder.finish()));
}
frame.present();
}
Ok(())
}
}
fn open_test_file(file_path: PathBuf, model: Rc<Model>) -> Rc<Model> {
let dem = Some(Rc::new(raster::Dem::load_from_image(&file_path)));
Rc::new(Model { dem, ..*model })
}