bevy/src/app/app_builder.rs
2020-02-07 22:42:30 -08:00

215 lines
7.1 KiB
Rust

use crate::{
app::{App, system_stage},
asset::*,
core::Time,
legion::prelude::{Runnable, Schedulable, Schedule, Universe, World},
render::render_graph_2,
render::render_graph_2::{pipelines::*, passes::*, wgpu_renderer::WgpuRenderer, resource_providers::*, UniformResourceProvider, StandardMaterial},
render::{passes::*, *},
plugin::load_plugin,
ui,
};
use bevy_transform::{transform_system_bundle, prelude::LocalToWorld};
use std::collections::HashMap;
pub struct AppBuilder {
pub world: World,
pub universe: Universe,
pub legacy_render_graph: Option<RenderGraph>,
pub renderer: Option<Box<dyn render_graph_2::Renderer>>,
pub render_graph_builder: render_graph_2::RenderGraphBuilder,
pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>,
pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>,
pub stage_order: Vec<String>,
}
impl AppBuilder {
pub fn new() -> Self {
let universe = Universe::new();
let world = universe.create_world();
AppBuilder {
universe,
world,
render_graph_builder: render_graph_2::RenderGraphBuilder::new(),
legacy_render_graph: None,
renderer: None,
system_stages: HashMap::new(),
runnable_stages: HashMap::new(),
stage_order: Vec::new(),
}
}
pub fn build(mut self) -> App {
let mut schedule_builder = Schedule::builder();
for stage_name in self.stage_order.iter() {
if let Some((_name, stage_systems)) = self.system_stages.remove_entry(stage_name) {
for system in stage_systems {
schedule_builder = schedule_builder.add_system(system);
}
schedule_builder = schedule_builder.flush();
}
if let Some((_name, stage_runnables)) = self.runnable_stages.remove_entry(stage_name) {
for system in stage_runnables {
schedule_builder = schedule_builder.add_thread_local(system);
}
schedule_builder = schedule_builder.flush();
}
}
App::new(
self.universe,
self.world,
schedule_builder.build(),
self.legacy_render_graph,
self.renderer,
self.render_graph_builder.build(),
)
}
pub fn run(self) {
self.build().run();
}
pub fn with_world(mut self, world: World) -> Self {
self.world = world;
self
}
pub fn setup_world(mut self, setup: impl Fn(&mut World)) -> Self {
setup(&mut self.world);
self
}
pub fn add_system(self, system: Box<dyn Schedulable>) -> Self {
self.add_system_to_stage(system_stage::UPDATE, system)
}
pub fn add_system_to_stage(mut self, stage_name: &str, system: Box<dyn Schedulable>) -> Self {
if let None = self.system_stages.get(stage_name) {
self.system_stages
.insert(stage_name.to_string(), Vec::new());
self.stage_order.push(stage_name.to_string());
}
let stages = self.system_stages.get_mut(stage_name).unwrap();
stages.push(system);
self
}
pub fn add_runnable_to_stage(mut self, stage_name: &str, system: Box<dyn Runnable>) -> Self {
if let None = self.runnable_stages.get(stage_name) {
self.runnable_stages
.insert(stage_name.to_string(), Vec::new());
self.stage_order.push(stage_name.to_string());
}
let stages = self.runnable_stages.get_mut(stage_name).unwrap();
stages.push(system);
self
}
pub fn with_legacy_render_graph(mut self) -> Self {
self.legacy_render_graph = Some(RenderGraph::new());
self
}
pub fn add_default_passes(mut self) -> Self {
let msaa_samples = 4;
{
let render_graph = &mut self.legacy_render_graph.as_mut().unwrap();
render_graph
.add_render_resource_manager(Box::new(render_resources::MaterialResourceManager));
render_graph.add_render_resource_manager(Box::new(
render_resources::LightResourceManager::new(10),
));
render_graph
.add_render_resource_manager(Box::new(render_resources::GlobalResourceManager));
render_graph
.add_render_resource_manager(Box::new(render_resources::Global2dResourceManager));
let depth_format = wgpu::TextureFormat::Depth32Float;
render_graph.set_pass(
"forward",
Box::new(ForwardPass::new(depth_format, msaa_samples)),
);
render_graph.set_pipeline(
"forward",
"forward",
Box::new(ForwardPipeline::new(msaa_samples)),
);
render_graph.set_pipeline(
"forward",
"forward_instanced",
Box::new(ForwardInstancedPipeline::new(depth_format, msaa_samples)),
);
render_graph.set_pipeline("forward", "ui", Box::new(UiPipeline::new(msaa_samples)));
}
self
}
pub fn add_default_resources(mut self) -> Self {
let resources = &mut self.world.resources;
resources.insert(Time::new());
resources.insert(AssetStorage::<Mesh>::new());
resources.insert(AssetStorage::<Texture>::new());
self
}
pub fn add_default_systems(mut self) -> Self {
self = self.add_system(ui::ui_update_system::build_ui_update_system());
for transform_system in transform_system_bundle::build(&mut self.world).drain(..) {
self = self.add_system(transform_system);
}
self
}
pub fn add_render_graph_defaults(mut self) -> Self {
self.render_graph_builder = self
.render_graph_builder
.add_resource_provider(Box::new(CameraResourceProvider))
.add_resource_provider(Box::new(Camera2dResourceProvider))
.add_resource_provider(Box::new(LightResourceProvider::new(10)))
.add_resource_provider(Box::new(UiResourceProvider::new()))
.add_resource_provider(Box::new(UniformResourceProvider::<StandardMaterial>::new()))
.add_resource_provider(Box::new(UniformResourceProvider::<LocalToWorld>::new()))
.add_forward_pass()
.add_forward_pipeline()
.add_ui_pipeline();
self
}
pub fn add_wgpu_renderer(mut self) -> Self {
self.renderer = Some(Box::new(WgpuRenderer::new()));
self
}
pub fn add_defaults_legacy(self) -> Self {
self.with_legacy_render_graph()
.add_default_resources()
.add_default_passes()
.add_default_systems()
}
pub fn add_defaults(self) -> Self {
self.add_default_resources()
.add_default_systems()
.add_render_graph_defaults()
.add_wgpu_renderer()
}
pub fn load_plugin(mut self, path: &str) -> Self {
let (_lib, plugin) = load_plugin(path);
self = plugin.build(self);
self
}
}