2022-05-15 21:30:05 +00:00
|
|
|
use crate::ui::ViewportWidget;
|
2022-05-15 19:40:25 +00:00
|
|
|
use crate::wgpu;
|
|
|
|
use cyborg::camera::Camera;
|
|
|
|
use cyborg::viewport::{Viewport, ViewportInfo, ViewportViews};
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
pub struct OffscreenTextures {
|
2022-05-15 20:49:50 +00:00
|
|
|
pub width: u32,
|
|
|
|
pub height: u32,
|
|
|
|
pub output_texture: wgpu::Texture,
|
|
|
|
pub output_view: wgpu::TextureView,
|
|
|
|
pub depth_texture: wgpu::Texture,
|
|
|
|
pub depth_view: wgpu::TextureView,
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl OffscreenTextures {
|
|
|
|
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
|
|
|
|
|
|
|
|
pub fn new(
|
|
|
|
device: &wgpu::Device,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
output_format: wgpu::TextureFormat,
|
|
|
|
) -> Self {
|
|
|
|
let size = wgpu::Extent3d {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
depth_or_array_layers: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut tex_desc = wgpu::TextureDescriptor {
|
|
|
|
label: None,
|
|
|
|
size,
|
|
|
|
mip_level_count: 1,
|
|
|
|
sample_count: 1,
|
|
|
|
dimension: wgpu::TextureDimension::D2,
|
|
|
|
format: output_format,
|
|
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
|
|
|
|
};
|
|
|
|
|
|
|
|
tex_desc.label = Some("Offscreen Output Texture");
|
|
|
|
let output_texture = device.create_texture(&tex_desc);
|
|
|
|
|
|
|
|
tex_desc.label = Some("Offscreen Depth Texture");
|
|
|
|
tex_desc.format = Self::DEPTH_FORMAT;
|
|
|
|
let depth_texture = device.create_texture(&tex_desc);
|
|
|
|
|
|
|
|
let view_desc = wgpu::TextureViewDescriptor::default();
|
|
|
|
let output_view = output_texture.create_view(&view_desc);
|
|
|
|
let depth_view = depth_texture.create_view(&view_desc);
|
|
|
|
|
|
|
|
Self {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
output_texture,
|
|
|
|
output_view,
|
|
|
|
depth_texture,
|
|
|
|
depth_view,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct OffscreenViewport {
|
2022-05-15 20:49:50 +00:00
|
|
|
pub device: Arc<wgpu::Device>,
|
|
|
|
pub queue: Arc<wgpu::Queue>,
|
|
|
|
pub output_format: wgpu::TextureFormat,
|
|
|
|
pub textures: OffscreenTextures,
|
|
|
|
pub egui_texture: egui::TextureId,
|
2022-05-15 21:30:05 +00:00
|
|
|
pub camera: Camera,
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl OffscreenViewport {
|
|
|
|
pub fn new(
|
|
|
|
device: Arc<wgpu::Device>,
|
|
|
|
queue: Arc<wgpu::Queue>,
|
|
|
|
output_format: wgpu::TextureFormat,
|
2022-05-15 20:49:50 +00:00
|
|
|
render_pass: &mut egui_wgpu_backend::RenderPass,
|
2022-05-15 19:40:25 +00:00
|
|
|
) -> Self {
|
|
|
|
let textures = OffscreenTextures::new(&device, 640, 480, output_format);
|
|
|
|
|
2022-05-15 20:49:50 +00:00
|
|
|
let egui_texture = render_pass.egui_texture_from_wgpu_texture(
|
|
|
|
&device,
|
|
|
|
&textures.output_view,
|
|
|
|
wgpu::FilterMode::Nearest,
|
|
|
|
);
|
|
|
|
|
2022-05-15 19:40:25 +00:00
|
|
|
Self {
|
|
|
|
device,
|
|
|
|
queue,
|
|
|
|
output_format,
|
|
|
|
textures,
|
2022-05-15 20:49:50 +00:00
|
|
|
egui_texture,
|
2022-05-15 21:30:05 +00:00
|
|
|
camera: Camera {
|
|
|
|
eye: [1.0, 1.0, 1.0, 0.0],
|
|
|
|
vp: Default::default(),
|
|
|
|
},
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_camera(&self) -> Camera {
|
2022-05-15 21:30:05 +00:00
|
|
|
self.camera.clone()
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Viewport for OffscreenViewport {
|
|
|
|
fn get_info(&self) -> ViewportInfo {
|
|
|
|
ViewportInfo {
|
|
|
|
output_format: self.output_format,
|
|
|
|
depth_format: OffscreenTextures::DEPTH_FORMAT,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_queue(&self) -> &wgpu::Queue {
|
|
|
|
&self.queue
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_views(&self) -> ViewportViews {
|
|
|
|
ViewportViews {
|
|
|
|
output: &self.textures.output_view,
|
|
|
|
depth: &self.textures.depth_view,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ViewportStore {
|
2022-05-15 20:49:50 +00:00
|
|
|
pub device: Arc<wgpu::Device>,
|
|
|
|
pub output_format: wgpu::TextureFormat,
|
|
|
|
pub viewport: OffscreenViewport,
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ViewportStore {
|
|
|
|
pub fn new(
|
|
|
|
device: Arc<wgpu::Device>,
|
|
|
|
queue: Arc<wgpu::Queue>,
|
|
|
|
output_format: wgpu::TextureFormat,
|
2022-05-15 20:49:50 +00:00
|
|
|
render_pass: &mut egui_wgpu_backend::RenderPass,
|
2022-05-15 19:40:25 +00:00
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
device: device.clone(),
|
|
|
|
output_format,
|
2022-05-15 20:49:50 +00:00
|
|
|
viewport: OffscreenViewport::new(device, queue, output_format, render_pass),
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl cyborg::legion::RenderCallbacks for ViewportStore {
|
|
|
|
fn get_viewports(&mut self) -> Vec<(&dyn Viewport, Camera)> {
|
|
|
|
vec![(&self.viewport, self.viewport.get_camera())]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn present(&mut self) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct RenderState {
|
|
|
|
pub world: legion::World,
|
|
|
|
pub resources: legion::Resources,
|
|
|
|
pub render_schedule: legion::Schedule,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderState {
|
|
|
|
pub fn new(
|
|
|
|
device: Arc<wgpu::Device>,
|
|
|
|
queue: Arc<wgpu::Queue>,
|
|
|
|
output_format: wgpu::TextureFormat,
|
2022-05-15 20:49:50 +00:00
|
|
|
render_pass: &mut egui_wgpu_backend::RenderPass,
|
2022-05-15 19:40:25 +00:00
|
|
|
) -> Self {
|
|
|
|
use cyborg::shader::{ShaderStore, ShaderWatcher};
|
|
|
|
|
|
|
|
let mut world = legion::World::default();
|
|
|
|
let mut resources = legion::Resources::default();
|
2022-05-15 20:49:50 +00:00
|
|
|
let viewport_store =
|
|
|
|
ViewportStore::new(device.clone(), queue.clone(), output_format, render_pass);
|
2022-05-15 19:40:25 +00:00
|
|
|
|
|
|
|
let renderer = cyborg::Renderer::new(device.clone(), queue.clone());
|
|
|
|
resources.insert(renderer);
|
|
|
|
|
|
|
|
let viewport_info = ViewportInfo {
|
|
|
|
output_format,
|
|
|
|
depth_format: OffscreenTextures::DEPTH_FORMAT,
|
|
|
|
};
|
|
|
|
resources.insert(viewport_info);
|
|
|
|
|
|
|
|
let shader_store = Arc::new(ShaderStore::new(device.clone()));
|
|
|
|
let shaders_dir = std::env::current_dir().unwrap();
|
|
|
|
let shaders_dir = shaders_dir.join("shaders/");
|
|
|
|
let shader_watcher = ShaderWatcher::new(shader_store.to_owned(), shaders_dir).unwrap();
|
|
|
|
|
|
|
|
let mesh_forward = shader_watcher.add_file("mesh_forward.wgsl").unwrap();
|
|
|
|
let mesh_skinning = shader_watcher.add_file("mesh_skinning.wgsl").unwrap();
|
|
|
|
|
|
|
|
let mesh_shaders = cyborg::pass::mesh::ShaderInfo {
|
|
|
|
store: shader_store.clone(),
|
|
|
|
forward: mesh_forward,
|
|
|
|
skinning: mesh_skinning,
|
|
|
|
};
|
|
|
|
|
|
|
|
resources.insert(mesh_shaders);
|
|
|
|
|
|
|
|
let mut render_schedule = legion::Schedule::builder();
|
|
|
|
cyborg::legion::build_renderer(viewport_store, &mut resources, &mut render_schedule);
|
|
|
|
let render_schedule = render_schedule.build();
|
|
|
|
|
|
|
|
world.push((
|
|
|
|
cyborg::scene::Transform {
|
|
|
|
transform: Default::default(),
|
|
|
|
},
|
|
|
|
cyborg::scene::DebugDrawList {
|
|
|
|
vertices: vec![
|
|
|
|
cyborg::scene::DebugVertex {
|
|
|
|
color: [1.0, 0.0, 0.0],
|
|
|
|
position: [0.0, 0.0, -1.0],
|
|
|
|
},
|
|
|
|
cyborg::scene::DebugVertex {
|
|
|
|
color: [0.0, 0.0, 1.0],
|
|
|
|
position: [0.0, 0.0, 1.0],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
indices: vec![0, 1],
|
|
|
|
},
|
|
|
|
));
|
|
|
|
|
|
|
|
Self {
|
|
|
|
world,
|
|
|
|
resources,
|
|
|
|
render_schedule,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-15 21:30:05 +00:00
|
|
|
pub fn update_viewport(&mut self, viewport: &mut ViewportWidget) {
|
|
|
|
let mut store = self.resources.get_mut::<ViewportStore>().unwrap();
|
|
|
|
store.viewport.camera = viewport.flycam.get_camera();
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:40:25 +00:00
|
|
|
pub fn render(&mut self) {
|
|
|
|
self.render_schedule
|
|
|
|
.execute(&mut self.world, &mut self.resources);
|
|
|
|
}
|
|
|
|
}
|