CommandBufferBuilder and setup systems
This commit is contained in:
		
							parent
							
								
									d2e160d44a
								
							
						
					
					
						commit
						c9aec26f88
					
				| @ -4,7 +4,7 @@ use darling::FromMeta; | |||||||
| use inflector::Inflector; | use inflector::Inflector; | ||||||
| use proc_macro::TokenStream; | use proc_macro::TokenStream; | ||||||
| use quote::{format_ident, quote}; | use quote::{format_ident, quote}; | ||||||
| use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Type}; | use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields, Ident, Type}; | ||||||
| 
 | 
 | ||||||
| #[derive(FromMeta, Debug, Default)] | #[derive(FromMeta, Debug, Default)] | ||||||
| struct EntityArchetypeAttributeArgs { | struct EntityArchetypeAttributeArgs { | ||||||
| @ -31,7 +31,8 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { | |||||||
|                 .find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag") |                 .find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag") | ||||||
|                 .is_some() |                 .is_some() | ||||||
|         }) |         }) | ||||||
|         .map(|field| &field.ident); |         .map(|field| field.ident.as_ref().unwrap()) | ||||||
|  |         .collect::<Vec<&Ident>>(); | ||||||
| 
 | 
 | ||||||
|     let component_fields = fields |     let component_fields = fields | ||||||
|         .iter() |         .iter() | ||||||
| @ -41,7 +42,8 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { | |||||||
|                 .find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag") |                 .find(|a| a.path.get_ident().as_ref().unwrap().to_string() == "tag") | ||||||
|                 .is_none() |                 .is_none() | ||||||
|         }) |         }) | ||||||
|         .map(|field| &field.ident); |         .map(|field| field.ident.as_ref().unwrap()) | ||||||
|  |         .collect::<Vec<&Ident>>(); | ||||||
| 
 | 
 | ||||||
|     let generics = ast.generics; |     let generics = ast.generics; | ||||||
|     let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl(); |     let (impl_generics, ty_generics, _where_clause) = generics.split_for_impl(); | ||||||
| @ -57,6 +59,14 @@ pub fn derive_entity_archetype(input: TokenStream) -> TokenStream { | |||||||
|                     ) |                     ) | ||||||
|                 ]).first().unwrap() |                 ]).first().unwrap() | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             fn insert_command_buffer(self, command_buffer: &mut bevy::prelude::CommandBuffer) -> Entity { | ||||||
|  |                 *command_buffer.insert((#(self.#tag_fields,)*), | ||||||
|  |                     vec![( | ||||||
|  |                         #(self.#component_fields,)* | ||||||
|  |                     ) | ||||||
|  |                 ]).first().unwrap() | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     }) |     }) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										65
									
								
								examples/setup_system.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								examples/setup_system.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | use bevy::prelude::*; | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     App::build().add_defaults().add_setup_system(setup()).run(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn setup() -> Box<dyn Schedulable> { | ||||||
|  |     SystemBuilder::new("setup") | ||||||
|  |         .write_resource::<AssetStorage<Mesh>>() | ||||||
|  |         .write_resource::<AssetStorage<StandardMaterial>>() | ||||||
|  |         .build(move |command_buffer, _, (meshes, materials), _| { | ||||||
|  |             let cube_handle = meshes.add(Mesh::load(MeshType::Cube)); | ||||||
|  |             let plane_handle = meshes.add(Mesh::load(MeshType::Plane { size: 10.0 })); | ||||||
|  |             let cube_material_handle = materials.add(StandardMaterial { | ||||||
|  |                 albedo: Color::rgb(0.5, 0.4, 0.3), | ||||||
|  |                 ..Default::default() | ||||||
|  |             }); | ||||||
|  |             let plane_material_handle = materials.add(StandardMaterial { | ||||||
|  |                 albedo: Color::rgb(0.1, 0.2, 0.1), | ||||||
|  |                 ..Default::default() | ||||||
|  |             }); | ||||||
|  |             
 | ||||||
|  |             command_buffer | ||||||
|  |                 .build() | ||||||
|  |                 // plane
 | ||||||
|  |                 .add_entity(MeshEntity { | ||||||
|  |                     mesh: plane_handle, | ||||||
|  |                     material: plane_material_handle, | ||||||
|  |                     // renderable: Renderable::instanced(),
 | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 // cube
 | ||||||
|  |                 .add_entity(MeshEntity { | ||||||
|  |                     mesh: cube_handle, | ||||||
|  |                     material: cube_material_handle, | ||||||
|  |                     // renderable: Renderable::instanced(),
 | ||||||
|  |                     translation: Translation::new(-1.5, 0.0, 1.0), | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 // cube
 | ||||||
|  |                 .add_entity(MeshEntity { | ||||||
|  |                     mesh: cube_handle, | ||||||
|  |                     material: cube_material_handle, | ||||||
|  |                     // renderable: Renderable::instanced(),
 | ||||||
|  |                     translation: Translation::new(1.5, 0.0, 1.0), | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 // light
 | ||||||
|  |                 .add_entity(LightEntity { | ||||||
|  |                     translation: Translation::new(4.0, -4.0, 5.0), | ||||||
|  |                     rotation: Rotation::from_euler_angles(0.0, 0.0, 0.0), | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 // camera
 | ||||||
|  |                 .add_entity(CameraEntity { | ||||||
|  |                     local_to_world: LocalToWorld(Mat4::look_at_rh( | ||||||
|  |                         Vec3::new(3.0, 8.0, 5.0), | ||||||
|  |                         Vec3::new(0.0, 0.0, 0.0), | ||||||
|  |                         Vec3::new(0.0, 0.0, 1.0), | ||||||
|  |                     )), | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }) | ||||||
|  |                 .build(); | ||||||
|  |         }) | ||||||
|  | } | ||||||
| @ -27,6 +27,7 @@ pub struct AppBuilder { | |||||||
|     pub universe: Universe, |     pub universe: Universe, | ||||||
|     pub renderer: Option<Box<dyn Renderer>>, |     pub renderer: Option<Box<dyn Renderer>>, | ||||||
|     pub render_graph_builder: RenderGraphBuilder, |     pub render_graph_builder: RenderGraphBuilder, | ||||||
|  |     pub setup_systems: Vec<Box<dyn Schedulable>>, | ||||||
|     pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>, |     pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>, | ||||||
|     pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>, |     pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>, | ||||||
|     pub stage_order: Vec<String>, |     pub stage_order: Vec<String>, | ||||||
| @ -43,6 +44,7 @@ impl AppBuilder { | |||||||
|             resources, |             resources, | ||||||
|             render_graph_builder: RenderGraphBuilder::new(), |             render_graph_builder: RenderGraphBuilder::new(), | ||||||
|             renderer: None, |             renderer: None, | ||||||
|  |             setup_systems: Vec::new(), | ||||||
|             system_stages: HashMap::new(), |             system_stages: HashMap::new(), | ||||||
|             runnable_stages: HashMap::new(), |             runnable_stages: HashMap::new(), | ||||||
|             stage_order: Vec::new(), |             stage_order: Vec::new(), | ||||||
| @ -50,6 +52,14 @@ impl AppBuilder { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn build(mut self) -> App { |     pub fn build(mut self) -> App { | ||||||
|  |         let mut setup_schedule_builder = Schedule::builder(); | ||||||
|  |         for setup_system in self.setup_systems { | ||||||
|  |             setup_schedule_builder = setup_schedule_builder.add_system(setup_system);    
 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut setup_schedule = setup_schedule_builder.build(); | ||||||
|  |         setup_schedule.execute(&mut self.world, &mut self.resources); | ||||||
|  | 
 | ||||||
|         let mut schedule_builder = Schedule::builder(); |         let mut schedule_builder = Schedule::builder(); | ||||||
|         for stage_name in self.stage_order.iter() { |         for stage_name in self.stage_order.iter() { | ||||||
|             if let Some((_name, stage_systems)) = self.system_stages.remove_entry(stage_name) { |             if let Some((_name, stage_systems)) = self.system_stages.remove_entry(stage_name) { | ||||||
| @ -99,6 +109,11 @@ impl AppBuilder { | |||||||
|         self.add_system_to_stage(system_stage::UPDATE, system) |         self.add_system_to_stage(system_stage::UPDATE, system) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn add_setup_system(mut self, system: Box<dyn Schedulable>) -> Self { | ||||||
|  |         self.setup_systems.push(system); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn add_system_to_stage(mut self, stage_name: &str, system: Box<dyn Schedulable>) -> Self { |     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) { |         if let None = self.system_stages.get(stage_name) { | ||||||
|             self.system_stages |             self.system_stages | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ use legion::prelude::*; | |||||||
| // builder macro that makes defaults easy? Object3dBuilder { Option<Material> } impl Builder for Object3dBuilder { }
 | // builder macro that makes defaults easy? Object3dBuilder { Option<Material> } impl Builder for Object3dBuilder { }
 | ||||||
| pub trait EntityArchetype { | pub trait EntityArchetype { | ||||||
|     fn insert(self, world: &mut World) -> Entity; |     fn insert(self, world: &mut World) -> Entity; | ||||||
|  |     fn insert_command_buffer(self, command_buffer: &mut CommandBuffer) -> Entity; | ||||||
| 
 | 
 | ||||||
|     // this would make composing entities from multiple archetypes possible
 |     // this would make composing entities from multiple archetypes possible
 | ||||||
|     // add_components appears to be missing from World. it will be less efficient without that
 |     // add_components appears to be missing from World. it will be less efficient without that
 | ||||||
|  | |||||||
| @ -95,3 +95,93 @@ impl<'a> WorldBuilder<'a> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub trait CommandBufferBuilderSource { | ||||||
|  |     fn build(&mut self) -> CommandBufferBuilder; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CommandBufferBuilderSource for CommandBuffer { | ||||||
|  |     fn build(&mut self) -> CommandBufferBuilder { | ||||||
|  |         CommandBufferBuilder { | ||||||
|  |             command_buffer: self, | ||||||
|  |             current_entity: None, | ||||||
|  |             parent_entity: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct CommandBufferBuilder<'a> { | ||||||
|  |     command_buffer: &'a mut CommandBuffer, | ||||||
|  |     current_entity: Option<Entity>, | ||||||
|  |     parent_entity: Option<Entity>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> CommandBufferBuilder<'a> { | ||||||
|  |     pub fn build_entity(mut self) -> Self { | ||||||
|  |         let entity = *self.command_buffer.insert((), vec![()]).first().unwrap(); | ||||||
|  |         self.current_entity = Some(entity); | ||||||
|  |         self.add_parent_to_current_entity(); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |     pub fn build(self) {} | ||||||
|  | 
 | ||||||
|  |     // note: this is slow and does a full entity copy
 | ||||||
|  |     pub fn add<T>(self, component: T) -> Self | ||||||
|  |     where | ||||||
|  |         T: legion::storage::Component, | ||||||
|  |     { | ||||||
|  |         let _ = self | ||||||
|  |             .command_buffer | ||||||
|  |             .add_component(*self.current_entity.as_ref().unwrap(), component); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn tag<T>(self, tag: T) -> Self | ||||||
|  |     where | ||||||
|  |         T: legion::storage::Tag, | ||||||
|  |     { | ||||||
|  |         let _ = self | ||||||
|  |             .command_buffer | ||||||
|  |             .add_tag(*self.current_entity.as_ref().unwrap(), tag); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn add_entities<T, C>(self, tags: T, components: C) -> Self | ||||||
|  |     where | ||||||
|  |         T: TagSet + TagLayout + for<'b> Filter<ChunksetFilterData<'b>> + 'static, | ||||||
|  |         C: IntoComponentSource + 'static, | ||||||
|  |     { | ||||||
|  |         self.command_buffer.insert(tags, components); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn add_entity(mut self, entity_archetype: impl EntityArchetype) -> Self { | ||||||
|  |         let current_entity = entity_archetype.insert_command_buffer(self.command_buffer); | ||||||
|  |         self.current_entity = Some(current_entity); | ||||||
|  |         self.add_parent_to_current_entity(); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn add_children(mut self, build_children: impl Fn(CommandBufferBuilder) -> CommandBufferBuilder) -> Self { | ||||||
|  |         self.parent_entity = self.current_entity; | ||||||
|  |         self.current_entity = None; | ||||||
|  | 
 | ||||||
|  |         self = build_children(self); | ||||||
|  | 
 | ||||||
|  |         self.current_entity = self.parent_entity; | ||||||
|  |         self.parent_entity = None; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn add_parent_to_current_entity(&mut self) { | ||||||
|  |         let current_entity = self.current_entity.unwrap(); | ||||||
|  |         if let Some(parent_entity) = self.parent_entity { | ||||||
|  |             let _ = self | ||||||
|  |                 .command_buffer | ||||||
|  |                 .add_component(current_entity, Parent(parent_entity)); | ||||||
|  |             let _ = self | ||||||
|  |                 .command_buffer | ||||||
|  |                 .add_component(current_entity, LocalToParent::identity()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ pub use crate::{ | |||||||
|     asset::{Asset, AssetStorage, Handle}, |     asset::{Asset, AssetStorage, Handle}, | ||||||
|     core::Time, |     core::Time, | ||||||
|     ecs, |     ecs, | ||||||
|     ecs::{default_archetypes::*, EntityArchetype, WorldBuilder, WorldBuilderSource}, |     ecs::{default_archetypes::*, EntityArchetype, WorldBuilder, WorldBuilderSource, CommandBufferBuilderSource}, | ||||||
|     render::{ |     render::{ | ||||||
|         mesh::{Mesh, MeshType}, |         mesh::{Mesh, MeshType}, | ||||||
|         pipeline::PipelineDescriptor, |         pipeline::PipelineDescriptor, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson