From 73eceb601e198a03de7822b97e3da81665ca06bd Mon Sep 17 00:00:00 2001 From: mars Date: Sun, 15 May 2022 13:40:25 -0600 Subject: [PATCH] Add RenderState --- editor/Cargo.toml | 4 +- editor/src/main.rs | 10 ++ editor/src/render.rs | 218 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 editor/src/render.rs diff --git a/editor/Cargo.toml b/editor/Cargo.toml index df33df7..7c0560f 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -4,10 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] -cyborg = { path = "../" } +cyborg = { path = "../", features = ["legion"] } egui = "0.17.0" egui-winit = "0.17.0" egui_wgpu_backend = "0.17.0" +glam = "0.20" +legion = "^0.4" pollster = "0.2" puffin = "^0.13" puffin_egui = "0.14.0" diff --git a/editor/src/main.rs b/editor/src/main.rs index 0dec69c..475ccb0 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -9,6 +9,7 @@ use egui_winit::winit::{ }; use std::sync::Arc; +mod render; mod ui; struct Application { @@ -22,6 +23,7 @@ struct Application { egui_ctx: egui::Context, egui_rp: EguiRenderPass, ui: ui::UserInterface, + render_state: render::RenderState, } impl Application { @@ -64,6 +66,8 @@ impl Application { let egui_ctx = egui::Context::default(); let egui_rp = egui_wgpu_backend::RenderPass::new(&device, config.format, 1); + let render_state = render::RenderState::new(device.clone(), queue.clone(), config.format); + Self { window, device, @@ -75,6 +79,7 @@ impl Application { egui_ctx, egui_rp, ui: ui::UserInterface::new(), + render_state, } } @@ -104,6 +109,11 @@ impl Application { self.egui_ctx.run(raw_input, |ctx| self.ui.run(ctx)) }; + { + puffin::profile_scope!("Main render"); + self.render_state.render(); + } + puffin::profile_scope!("Render egui"); self.egui_state.handle_platform_output( diff --git a/editor/src/render.rs b/editor/src/render.rs new file mode 100644 index 0000000..685a1a4 --- /dev/null +++ b/editor/src/render.rs @@ -0,0 +1,218 @@ +use crate::wgpu; +use cyborg::camera::Camera; +use cyborg::viewport::{Viewport, ViewportInfo, ViewportViews}; +use std::sync::Arc; + +pub struct OffscreenTextures { + width: u32, + height: u32, + output_texture: wgpu::Texture, + output_view: wgpu::TextureView, + depth_texture: wgpu::Texture, + depth_view: wgpu::TextureView, +} + +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 { + device: Arc, + queue: Arc, + output_format: wgpu::TextureFormat, + textures: OffscreenTextures, +} + +impl OffscreenViewport { + pub fn new( + device: Arc, + queue: Arc, + output_format: wgpu::TextureFormat, + ) -> Self { + let textures = OffscreenTextures::new(&device, 640, 480, output_format); + + Self { + device, + queue, + output_format, + textures, + } + } + + pub fn get_camera(&self) -> Camera { + Camera { + eye: [1.0, 1.0, 1.0, 0.0], + vp: Default::default(), + } + } +} + +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 { + device: Arc, + output_format: wgpu::TextureFormat, + viewport: OffscreenViewport, +} + +impl ViewportStore { + pub fn new( + device: Arc, + queue: Arc, + output_format: wgpu::TextureFormat, + ) -> Self { + Self { + device: device.clone(), + output_format, + viewport: OffscreenViewport::new(device, queue, output_format), + } + } +} + +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, + queue: Arc, + output_format: wgpu::TextureFormat, + ) -> Self { + use cyborg::shader::{ShaderStore, ShaderWatcher}; + + let mut world = legion::World::default(); + let mut resources = legion::Resources::default(); + let viewport_store = ViewportStore::new(device.clone(), queue.clone(), output_format); + + 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, + } + } + + pub fn render(&mut self) { + self.render_schedule + .execute(&mut self.world, &mut self.resources); + } +}