Initial Legion support
This commit is contained in:
parent
77e4b4dc4b
commit
d44db2c05f
|
@ -18,6 +18,14 @@ strum = { version = "0.24", features = ["derive"] }
|
||||||
wgpu = "^0.12"
|
wgpu = "^0.12"
|
||||||
winit = "0.26"
|
winit = "0.26"
|
||||||
|
|
||||||
|
[dependencies.legion]
|
||||||
|
version = "^0.4"
|
||||||
|
optional = true
|
||||||
|
|
||||||
[dependencies.naga]
|
[dependencies.naga]
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
features = ["wgsl-in", "glsl-in", "wgsl-out", "serialize", "deserialize"]
|
features = ["wgsl-in", "glsl-in", "wgsl-out", "serialize", "deserialize"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "cyborg"
|
||||||
|
required-features = ["legion"]
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
//! [Legion](https://github.com/amethyst/legion) integration.
|
||||||
|
|
||||||
|
use crate::camera::Camera;
|
||||||
|
use crate::pass::{self, debug, mesh};
|
||||||
|
use crate::scene;
|
||||||
|
use crate::viewport::{ViewportInfo, WinitViewport};
|
||||||
|
use crate::Renderer;
|
||||||
|
use legion::systems::Builder;
|
||||||
|
use legion::world::SubWorld;
|
||||||
|
use legion::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Initializes the Cyborg renderer within a Legion world.
|
||||||
|
///
|
||||||
|
/// Uses the provided [Builder] to run all rendering code.
|
||||||
|
///
|
||||||
|
/// Required pre-initialized resources:
|
||||||
|
/// - [Renderer]
|
||||||
|
/// - [ViewportInfo] (TODO: dynamic viewport targeting)
|
||||||
|
/// - [mesh::ShaderInfo]
|
||||||
|
pub fn build_renderer(resources: &mut Resources, builder: &mut Builder) {
|
||||||
|
let renderer = resources.get_mut::<Renderer>().unwrap();
|
||||||
|
let viewport_info = resources.get::<ViewportInfo>().unwrap();
|
||||||
|
let mesh_shaders = resources.get::<mesh::ShaderInfo>().unwrap();
|
||||||
|
|
||||||
|
let device = renderer.get_device();
|
||||||
|
let layouts = renderer.get_layouts();
|
||||||
|
|
||||||
|
let mesh_pass = mesh::MeshPass::new(
|
||||||
|
device.to_owned(),
|
||||||
|
layouts.to_owned(),
|
||||||
|
viewport_info.to_owned(),
|
||||||
|
mesh_shaders.to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let debug_pass = debug::DebugPass::new(
|
||||||
|
device.to_owned(),
|
||||||
|
layouts.to_owned(),
|
||||||
|
viewport_info.to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let frames_in_flight = renderer.get_frames_in_flight();
|
||||||
|
let mesh_pass = pass::RenderPassBox::new(Arc::new(mesh_pass), frames_in_flight);
|
||||||
|
let debug_pass = pass::RenderPassBox::new(Arc::new(debug_pass), frames_in_flight);
|
||||||
|
|
||||||
|
// drop borrowed resources so that new ones can be inserted
|
||||||
|
drop(renderer);
|
||||||
|
drop(viewport_info);
|
||||||
|
drop(mesh_shaders);
|
||||||
|
|
||||||
|
resources.insert(mesh_pass);
|
||||||
|
resources.insert(debug_pass);
|
||||||
|
|
||||||
|
builder.add_system(draw_transformed_meshes_system());
|
||||||
|
builder.add_system(render_system());
|
||||||
|
builder.add_system(present_winit_system());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[system]
|
||||||
|
#[read_component(WinitViewport)]
|
||||||
|
#[read_component(Camera)]
|
||||||
|
fn render(
|
||||||
|
world: &mut SubWorld,
|
||||||
|
#[resource] renderer: &mut Renderer,
|
||||||
|
#[resource] mesh_pass: &mut pass::RenderPassBox<mesh::MeshPass>,
|
||||||
|
#[resource] debug_pass: &mut pass::RenderPassBox<debug::DebugPass>,
|
||||||
|
) {
|
||||||
|
let target_query: Vec<_> = <(&WinitViewport, &Camera)>::query().iter(world).collect();
|
||||||
|
if target_query.len() > 1 {
|
||||||
|
eprintln!("Cyborg does not currently support more than one viewport at a time!");
|
||||||
|
return;
|
||||||
|
} else if let Some((viewport, camera)) = target_query.get(0) {
|
||||||
|
let mut passes: Vec<&mut dyn pass::RenderPassBoxTrait> = Vec::new();
|
||||||
|
passes.push(mesh_pass);
|
||||||
|
passes.push(debug_pass);
|
||||||
|
renderer.render(passes.as_mut_slice(), *viewport, camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[system]
|
||||||
|
fn draw_transformed_meshes(
|
||||||
|
#[resource] mesh_pass: &pass::RenderPassBox<mesh::MeshPass>,
|
||||||
|
world: &mut SubWorld,
|
||||||
|
query: &mut Query<&scene::TransformedMesh>,
|
||||||
|
) {
|
||||||
|
let transformed: Vec<_> = query.iter(world).map(|m| m.clone()).collect();
|
||||||
|
mesh_pass
|
||||||
|
.get_meshes()
|
||||||
|
.write()
|
||||||
|
.transformed
|
||||||
|
.extend_from_slice(transformed.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[system(for_each)]
|
||||||
|
fn present_winit(viewport: &mut WinitViewport) {
|
||||||
|
viewport.present();
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
//! Cyborg is a high-performance, modern, experimental rendering engine written
|
//! Cyborg is a high-performance, modern, experimental rendering engine written
|
||||||
//! in Rust.
|
//! in Rust.
|
||||||
|
//!
|
||||||
|
//! # Features
|
||||||
|
//!
|
||||||
|
//! - `legion`: Enables [Legion](https://github.com/amethyst/legion) integration
|
||||||
|
//! for Cyborg. Disabled by default.
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
@ -14,6 +19,9 @@ pub mod staging;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod viewport;
|
pub mod viewport;
|
||||||
|
|
||||||
|
#[cfg(feature = "legion")]
|
||||||
|
pub mod legion;
|
||||||
|
|
||||||
use camera::Camera;
|
use camera::Camera;
|
||||||
use pass::*;
|
use pass::*;
|
||||||
use phase::*;
|
use phase::*;
|
||||||
|
|
93
src/main.rs
93
src/main.rs
|
@ -1,6 +1,10 @@
|
||||||
|
use cyborg::camera::Camera;
|
||||||
|
use cyborg::pass::{mesh, RenderPassBox};
|
||||||
use cyborg::shader;
|
use cyborg::shader;
|
||||||
use cyborg::storage::mesh::*;
|
use cyborg::storage::mesh::*;
|
||||||
use cyborg::{pass, viewport::*, Renderer};
|
use cyborg::viewport::*;
|
||||||
|
use cyborg::Renderer;
|
||||||
|
use legion::*;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
|
@ -12,16 +16,19 @@ fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
let mut viewport = pollster::block_on(WinitViewport::from_window(&window));
|
let mut viewport = pollster::block_on(WinitViewport::from_window(&window));
|
||||||
let mut renderer = Renderer::new(viewport.device.clone(), viewport.queue.clone());
|
|
||||||
|
let mut world = World::new(Default::default());
|
||||||
|
let mut resources = Resources::default();
|
||||||
|
|
||||||
|
let renderer = Renderer::new(viewport.device.clone(), viewport.queue.clone());
|
||||||
|
resources.insert(renderer);
|
||||||
|
|
||||||
|
resources.insert(viewport.get_info().to_owned());
|
||||||
|
|
||||||
let mut flycam = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
|
let mut flycam = cyborg::camera::Flycam::new(0.002, 10.0, 0.25);
|
||||||
let mut is_grabbed = false;
|
let mut is_grabbed = false;
|
||||||
|
|
||||||
let device = renderer.get_device();
|
let shader_store = Arc::new(shader::ShaderStore::new(viewport.device.clone()));
|
||||||
let layouts = renderer.get_layouts();
|
|
||||||
|
|
||||||
let shader_store = Arc::new(shader::ShaderStore::new(device.to_owned()));
|
|
||||||
|
|
||||||
let shaders_dir = std::env::current_dir().unwrap();
|
let shaders_dir = std::env::current_dir().unwrap();
|
||||||
let shaders_dir = shaders_dir.join("shaders/");
|
let shaders_dir = shaders_dir.join("shaders/");
|
||||||
let shader_watcher = shader::ShaderWatcher::new(shader_store.to_owned(), shaders_dir).unwrap();
|
let shader_watcher = shader::ShaderWatcher::new(shader_store.to_owned(), shaders_dir).unwrap();
|
||||||
|
@ -29,43 +36,46 @@ fn main() {
|
||||||
let mesh_forward = shader_watcher.add_file("mesh_forward.wgsl").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_skinning = shader_watcher.add_file("mesh_skinning.wgsl").unwrap();
|
||||||
|
|
||||||
let mesh_shaders = pass::mesh::ShaderInfo {
|
let mesh_shaders = mesh::ShaderInfo {
|
||||||
store: shader_store.clone(),
|
store: shader_store.clone(),
|
||||||
forward: mesh_forward,
|
forward: mesh_forward,
|
||||||
skinning: mesh_skinning,
|
skinning: mesh_skinning,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mesh_pass = pass::mesh::MeshPass::new(
|
resources.insert(mesh_shaders);
|
||||||
device.to_owned(),
|
|
||||||
layouts.to_owned(),
|
let mut render_schedule = Schedule::builder();
|
||||||
viewport.get_info(),
|
cyborg::legion::build_renderer(&mut resources, &mut render_schedule);
|
||||||
mesh_shaders,
|
let mut render_schedule = render_schedule.build();
|
||||||
);
|
|
||||||
let debug_pass =
|
|
||||||
pass::debug::DebugPass::new(device.to_owned(), layouts.to_owned(), viewport.get_info());
|
|
||||||
|
|
||||||
let example_vertices = vec![
|
let example_vertices = vec![
|
||||||
pass::mesh::Vertex {
|
mesh::Vertex {
|
||||||
position: [-0.5, 0.5, 0.0],
|
position: [-0.5, 0.0, 0.5],
|
||||||
tan_frame: 0,
|
tan_frame: 0,
|
||||||
},
|
},
|
||||||
pass::mesh::Vertex {
|
mesh::Vertex {
|
||||||
position: [0.5, 0.5, 0.0],
|
position: [0.5, 0.0, 0.5],
|
||||||
tan_frame: 0,
|
tan_frame: 0,
|
||||||
},
|
},
|
||||||
pass::mesh::Vertex {
|
mesh::Vertex {
|
||||||
position: [0.0, -0.5, 0.0],
|
position: [0.0, -0.5, -0.5],
|
||||||
|
tan_frame: 0,
|
||||||
|
},
|
||||||
|
mesh::Vertex {
|
||||||
|
position: [0.0, 0.5, -0.5],
|
||||||
tan_frame: 0,
|
tan_frame: 0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let mesh_pass = resources.get::<RenderPassBox<mesh::MeshPass>>().unwrap();
|
||||||
|
|
||||||
let example_vertices = AttrBuffer {
|
let example_vertices = AttrBuffer {
|
||||||
id: mesh_pass.get_vertex_attr_id(),
|
id: mesh_pass.get_vertex_attr_id(),
|
||||||
count: example_vertices.len(),
|
count: example_vertices.len(),
|
||||||
data: bytemuck::cast_slice(&example_vertices).to_vec(),
|
data: bytemuck::cast_slice(&example_vertices).to_vec(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let example_indices = vec![0u32, 1u32, 2u32];
|
let example_indices: Vec<mesh::Index> = vec![0, 1, 2, 1, 2, 3, 2, 3, 0, 0, 2, 3];
|
||||||
let example_indices = AttrBuffer {
|
let example_indices = AttrBuffer {
|
||||||
id: mesh_pass.get_index_attr_id(),
|
id: mesh_pass.get_index_attr_id(),
|
||||||
count: example_indices.len(),
|
count: example_indices.len(),
|
||||||
|
@ -77,40 +87,37 @@ fn main() {
|
||||||
example_mesh.attributes.push(example_indices);
|
example_mesh.attributes.push(example_indices);
|
||||||
let example_mesh = mesh_pass.get_mesh_pool().load(example_mesh).unwrap();
|
let example_mesh = mesh_pass.get_mesh_pool().load(example_mesh).unwrap();
|
||||||
|
|
||||||
let meshes = mesh_pass.get_meshes().to_owned();
|
drop(mesh_pass);
|
||||||
|
|
||||||
let r = 8;
|
let r = 4;
|
||||||
let mut meshes_lock = meshes.write();
|
|
||||||
for x in -r..r {
|
for x in -r..r {
|
||||||
for y in -r..r {
|
for y in -r..r {
|
||||||
for z in -r..r {
|
for z in -r..r {
|
||||||
let translation = glam::Vec3::new(x as f32, y as f32, z as f32);
|
let translation = glam::Vec3::new(x as f32, y as f32, z as f32);
|
||||||
let transform = glam::Mat4::from_translation(translation);
|
let transform = glam::Mat4::from_translation(translation);
|
||||||
meshes_lock.transformed.push(cyborg::scene::TransformedMesh {
|
world.push((
|
||||||
transform,
|
cyborg::scene::TransformedMesh {
|
||||||
mesh: example_mesh.clone(),
|
transform,
|
||||||
});
|
mesh: example_mesh.clone(),
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(meshes_lock);
|
|
||||||
|
|
||||||
let frames_in_flight = renderer.get_frames_in_flight();
|
let viewport_entity = world.push((viewport, flycam.get_camera()));
|
||||||
let mut mesh_pass = pass::RenderPassBox::new(Arc::new(mesh_pass), frames_in_flight);
|
|
||||||
let mut debug_pass = pass::RenderPassBox::new(Arc::new(debug_pass), frames_in_flight);
|
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
Event::RedrawRequested(_) => {
|
Event::RedrawRequested(_) => {
|
||||||
|
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
||||||
|
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
||||||
match viewport.acquire() {
|
match viewport.acquire() {
|
||||||
Err(wgpu::SurfaceError::Lost) => viewport.resize(viewport.size),
|
Err(wgpu::SurfaceError::Lost) => viewport.resize(viewport.size),
|
||||||
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
||||||
Err(e) => eprintln!("error: {:?}", e),
|
Err(e) => eprintln!("error: {:?}", e),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let mut passes: Vec<&mut dyn pass::RenderPassBoxTrait> = Vec::new();
|
render_schedule.execute(&mut world, &mut resources);
|
||||||
passes.push(&mut mesh_pass);
|
|
||||||
passes.push(&mut debug_pass);
|
|
||||||
renderer.render(passes.as_mut_slice(), &viewport, &flycam.get_camera());
|
|
||||||
viewport.present();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +125,10 @@ fn main() {
|
||||||
shader_watcher.watch();
|
shader_watcher.watch();
|
||||||
flycam.update();
|
flycam.update();
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
|
|
||||||
|
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
||||||
|
let camera = viewport_entry.get_component_mut::<Camera>().unwrap();
|
||||||
|
let _ = std::mem::replace(camera, flycam.get_camera());
|
||||||
}
|
}
|
||||||
Event::DeviceEvent { ref event, .. } => match event {
|
Event::DeviceEvent { ref event, .. } => match event {
|
||||||
DeviceEvent::MouseMotion { delta } => {
|
DeviceEvent::MouseMotion { delta } => {
|
||||||
|
@ -163,9 +174,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
WindowEvent::Resized(physical_size) => {
|
WindowEvent::Resized(physical_size) => {
|
||||||
|
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
||||||
|
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
||||||
viewport.resize(*physical_size);
|
viewport.resize(*physical_size);
|
||||||
}
|
}
|
||||||
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||||
|
let mut viewport_entry = world.entry_mut(viewport_entity).unwrap();
|
||||||
|
let viewport = viewport_entry.get_component_mut::<WinitViewport>().unwrap();
|
||||||
viewport.resize(**new_inner_size);
|
viewport.resize(**new_inner_size);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -306,10 +306,10 @@ impl RenderPass for MeshPass {
|
||||||
data.groups.clear();
|
data.groups.clear();
|
||||||
data.skinning_uniforms.clear();
|
data.skinning_uniforms.clear();
|
||||||
|
|
||||||
let meshes_read = self.meshes.read();
|
let mut meshes_lock = self.meshes.write();
|
||||||
let mesh_bindings = self
|
let mesh_bindings = self
|
||||||
.mesh_pool
|
.mesh_pool
|
||||||
.iter_meshes(self.mesh_layout_id, meshes_read.transformed.iter(), |i| {
|
.iter_meshes(self.mesh_layout_id, meshes_lock.transformed.iter(), |i| {
|
||||||
&i.mesh
|
&i.mesh
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -398,6 +398,8 @@ impl RenderPass for MeshPass {
|
||||||
data.skinned_vertices.reserve(skinned_cursor);
|
data.skinned_vertices.reserve(skinned_cursor);
|
||||||
data.skinned_vertices.write(&queue);
|
data.skinned_vertices.write(&queue);
|
||||||
data.skinning_uniforms.write(&queue);
|
data.skinning_uniforms.write(&queue);
|
||||||
|
|
||||||
|
meshes_lock.transformed.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_commands(&self, data: PhaseData<&FrameData>, cmds: &mut wgpu::CommandEncoder) {
|
fn record_commands(&self, data: PhaseData<&FrameData>, cmds: &mut wgpu::CommandEncoder) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::storage::mesh::MeshHandle;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct TransformedMesh {
|
pub struct TransformedMesh {
|
||||||
pub transform: glam::Mat4,
|
pub transform: glam::Mat4,
|
||||||
pub mesh: MeshHandle,
|
pub mesh: MeshHandle,
|
||||||
|
|
Loading…
Reference in New Issue