cyborg/src/legion.rs

98 lines
3.0 KiB
Rust

//! [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();
}