2022-05-19 02:00:02 +00:00
|
|
|
use crate::model;
|
|
|
|
use crate::ui::{ObjectWidget, ViewportWidget};
|
2022-05-15 19:40:25 +00:00
|
|
|
use crate::wgpu;
|
|
|
|
use cyborg::camera::Camera;
|
2022-05-19 02:00:02 +00:00
|
|
|
use cyborg::storage::mesh::MeshHandle;
|
2022-05-15 19:40:25 +00:00
|
|
|
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 {
|
2022-06-29 04:56:12 +00:00
|
|
|
use cyborg::scene::{DebugDrawList, DebugVertex};
|
2022-05-15 19:40:25 +00:00
|
|
|
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();
|
|
|
|
|
2022-06-29 02:41:01 +00:00
|
|
|
// make debug draw grid
|
2022-06-30 11:51:34 +00:00
|
|
|
let grid_size = 100;
|
2022-06-29 02:41:01 +00:00
|
|
|
let grid_color = [0.0, 1.0, 0.0];
|
|
|
|
let mut grid_vertices = Vec::new();
|
|
|
|
|
|
|
|
// draw horizontal lines
|
|
|
|
for x in -grid_size..=grid_size {
|
|
|
|
grid_vertices.push(DebugVertex {
|
|
|
|
position: [x as f32, 0.0, -grid_size as f32],
|
|
|
|
color: grid_color.clone(),
|
|
|
|
});
|
|
|
|
grid_vertices.push(DebugVertex {
|
|
|
|
position: [x as f32, 0.0, grid_size as f32],
|
|
|
|
color: grid_color.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw vertical lines
|
|
|
|
for z in -grid_size..=grid_size {
|
|
|
|
grid_vertices.push(DebugVertex {
|
|
|
|
position: [-grid_size as f32, 0.0, z as f32],
|
|
|
|
color: grid_color.clone(),
|
|
|
|
});
|
|
|
|
grid_vertices.push(DebugVertex {
|
|
|
|
position: [grid_size as f32, 0.0, z as f32],
|
|
|
|
color: grid_color.clone(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-05-15 19:40:25 +00:00
|
|
|
world.push((
|
|
|
|
cyborg::scene::Transform {
|
|
|
|
transform: Default::default(),
|
|
|
|
},
|
2022-06-29 02:41:01 +00:00
|
|
|
DebugDrawList {
|
|
|
|
indices: (0..(grid_vertices.len() as u32)).into_iter().collect(),
|
|
|
|
vertices: grid_vertices,
|
2022-05-15 19:40:25 +00:00
|
|
|
},
|
|
|
|
));
|
|
|
|
|
|
|
|
Self {
|
|
|
|
world,
|
|
|
|
resources,
|
|
|
|
render_schedule,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-15 22:06:42 +00:00
|
|
|
pub fn update_viewport(
|
|
|
|
&mut self,
|
|
|
|
egui_rp: &mut egui_wgpu_backend::RenderPass,
|
|
|
|
widget: &mut ViewportWidget,
|
|
|
|
) {
|
2022-05-15 21:30:05 +00:00
|
|
|
let mut store = self.resources.get_mut::<ViewportStore>().unwrap();
|
2022-05-15 22:06:42 +00:00
|
|
|
let mut viewport = &mut store.viewport;
|
|
|
|
viewport.camera = widget.flycam.get_camera();
|
|
|
|
|
|
|
|
if viewport.textures.width != widget.width || viewport.textures.height != widget.height {
|
|
|
|
viewport.textures = OffscreenTextures::new(
|
|
|
|
&viewport.device,
|
|
|
|
widget.width,
|
|
|
|
widget.height,
|
|
|
|
viewport.output_format,
|
|
|
|
);
|
|
|
|
|
|
|
|
egui_rp
|
|
|
|
.update_egui_texture_from_wgpu_texture(
|
|
|
|
&viewport.device,
|
|
|
|
&viewport.textures.output_view,
|
|
|
|
wgpu::FilterMode::Nearest,
|
|
|
|
viewport.egui_texture,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
}
|
2022-05-15 21:30:05 +00:00
|
|
|
}
|
|
|
|
|
2022-05-15 19:40:25 +00:00
|
|
|
pub fn render(&mut self) {
|
|
|
|
self.render_schedule
|
|
|
|
.execute(&mut self.world, &mut self.resources);
|
|
|
|
}
|
2022-05-19 02:00:02 +00:00
|
|
|
|
2022-06-29 04:56:12 +00:00
|
|
|
pub fn load_model(&mut self, model: &model::Model) -> model::LoadedModel {
|
|
|
|
model::LoadedModel {
|
|
|
|
name: model.name.clone(),
|
|
|
|
objects: model.objects.iter().map(|o| self.load_object(o)).collect(),
|
2022-05-19 02:00:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-29 04:56:12 +00:00
|
|
|
pub fn load_object(&mut self, object: &model::Object) -> model::LoadedObject {
|
|
|
|
model::LoadedObject {
|
2022-05-19 02:00:02 +00:00
|
|
|
name: object.name.clone(),
|
2022-05-21 03:18:01 +00:00
|
|
|
transform: object.transform.clone(),
|
2022-06-29 04:56:12 +00:00
|
|
|
meshes: object.meshes.iter().map(|m| self.load_mesh(m)).collect(),
|
|
|
|
children: object
|
|
|
|
.children
|
|
|
|
.iter()
|
|
|
|
.map(|o| self.load_object(o))
|
|
|
|
.collect(),
|
2022-05-19 02:00:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-21 03:18:01 +00:00
|
|
|
pub fn load_mesh(&mut self, data: &model::Mesh) -> MeshHandle {
|
2022-05-19 02:00:02 +00:00
|
|
|
use cyborg::pass::{
|
|
|
|
mesh::{MeshPass, Vertex},
|
|
|
|
RenderPassBox,
|
|
|
|
};
|
|
|
|
use cyborg::storage::mesh::{AttrBuffer, MeshBuffer};
|
|
|
|
|
|
|
|
let mesh_pass = self.resources.get::<RenderPassBox<MeshPass>>().unwrap();
|
|
|
|
let attributes = mesh_pass.get_attributes();
|
|
|
|
|
|
|
|
let vertices: Vec<_> = data
|
|
|
|
.vertices
|
|
|
|
.iter()
|
|
|
|
.map(|v| Vertex {
|
|
|
|
position: v.position.to_array(),
|
|
|
|
tan_frame: 0, // TODO encode tangents
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let vertices = AttrBuffer {
|
|
|
|
id: attributes.vertex,
|
|
|
|
count: vertices.len(),
|
|
|
|
data: bytemuck::cast_slice(&vertices).to_vec(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let indices = AttrBuffer {
|
|
|
|
id: attributes.index,
|
|
|
|
count: data.indices.len(),
|
|
|
|
data: bytemuck::cast_slice(&data.indices).to_vec(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut mesh = MeshBuffer::default();
|
|
|
|
mesh.attributes.push(vertices);
|
|
|
|
mesh.attributes.push(indices);
|
|
|
|
|
|
|
|
mesh_pass.get_mesh_pool().load(mesh).unwrap()
|
|
|
|
}
|
2022-06-29 04:56:12 +00:00
|
|
|
|
2022-06-30 06:22:24 +00:00
|
|
|
pub fn spawn_model(
|
|
|
|
&mut self,
|
|
|
|
model: &model::LoadedModel,
|
|
|
|
transform: &glam::Mat4,
|
|
|
|
) -> Vec<ObjectWidget> {
|
2022-06-29 04:56:12 +00:00
|
|
|
// TODO use model name?
|
|
|
|
let mut objects = Vec::new();
|
|
|
|
for object in model.objects.iter() {
|
2022-06-30 06:22:24 +00:00
|
|
|
objects.push(self.spawn_object(object, transform));
|
2022-06-29 04:56:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
objects
|
|
|
|
}
|
|
|
|
|
2022-06-30 06:22:24 +00:00
|
|
|
pub fn spawn_object(
|
|
|
|
&mut self,
|
|
|
|
object: &model::LoadedObject,
|
|
|
|
root_transform: &glam::Mat4,
|
|
|
|
) -> ObjectWidget {
|
2022-06-29 04:56:12 +00:00
|
|
|
let transform = cyborg::scene::Transform {
|
2022-06-30 06:22:24 +00:00
|
|
|
transform: *root_transform * object.transform.to_mat4(),
|
2022-06-29 04:56:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut entities = Vec::new();
|
|
|
|
for mesh in object.meshes.iter() {
|
|
|
|
let mesh = cyborg::scene::Mesh { mesh: *mesh };
|
|
|
|
let entity = self.world.push((mesh, transform.clone()));
|
|
|
|
entities.push(entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut children = Vec::new();
|
|
|
|
for child in object.children.iter() {
|
2022-06-30 06:22:24 +00:00
|
|
|
children.push(self.spawn_object(child, root_transform));
|
2022-06-29 04:56:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ObjectWidget {
|
|
|
|
name: object.name.clone(),
|
|
|
|
transform: object.transform.clone(),
|
|
|
|
entities,
|
|
|
|
children,
|
|
|
|
dirty: false,
|
|
|
|
children_dirty: false,
|
|
|
|
}
|
|
|
|
}
|
2022-05-15 19:40:25 +00:00
|
|
|
}
|