CommandBufferBuilder and setup systems
This commit is contained in:
		
							parent
							
								
									d2e160d44a
								
							
						
					
					
						commit
						c9aec26f88
					
				| @ -4,7 +4,7 @@ use darling::FromMeta; | ||||
| use inflector::Inflector; | ||||
| use proc_macro::TokenStream; | ||||
| 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)] | ||||
| 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") | ||||
|                 .is_some() | ||||
|         }) | ||||
|         .map(|field| &field.ident); | ||||
|         .map(|field| field.ident.as_ref().unwrap()) | ||||
|         .collect::<Vec<&Ident>>(); | ||||
| 
 | ||||
|     let component_fields = fields | ||||
|         .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") | ||||
|                 .is_none() | ||||
|         }) | ||||
|         .map(|field| &field.ident); | ||||
|         .map(|field| field.ident.as_ref().unwrap()) | ||||
|         .collect::<Vec<&Ident>>(); | ||||
| 
 | ||||
|     let generics = ast.generics; | ||||
|     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() | ||||
|             } | ||||
| 
 | ||||
|             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 renderer: Option<Box<dyn Renderer>>, | ||||
|     pub render_graph_builder: RenderGraphBuilder, | ||||
|     pub setup_systems: Vec<Box<dyn Schedulable>>, | ||||
|     pub system_stages: HashMap<String, Vec<Box<dyn Schedulable>>>, | ||||
|     pub runnable_stages: HashMap<String, Vec<Box<dyn Runnable>>>, | ||||
|     pub stage_order: Vec<String>, | ||||
| @ -43,6 +44,7 @@ impl AppBuilder { | ||||
|             resources, | ||||
|             render_graph_builder: RenderGraphBuilder::new(), | ||||
|             renderer: None, | ||||
|             setup_systems: Vec::new(), | ||||
|             system_stages: HashMap::new(), | ||||
|             runnable_stages: HashMap::new(), | ||||
|             stage_order: Vec::new(), | ||||
| @ -50,6 +52,14 @@ impl AppBuilder { | ||||
|     } | ||||
| 
 | ||||
|     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(); | ||||
|         for stage_name in self.stage_order.iter() { | ||||
|             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) | ||||
|     } | ||||
| 
 | ||||
|     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 { | ||||
|         if let None = self.system_stages.get(stage_name) { | ||||
|             self.system_stages | ||||
|  | ||||
| @ -3,6 +3,7 @@ use legion::prelude::*; | ||||
| // builder macro that makes defaults easy? Object3dBuilder { Option<Material> } impl Builder for Object3dBuilder { }
 | ||||
| pub trait EntityArchetype { | ||||
|     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
 | ||||
|     // 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}, | ||||
|     core::Time, | ||||
|     ecs, | ||||
|     ecs::{default_archetypes::*, EntityArchetype, WorldBuilder, WorldBuilderSource}, | ||||
|     ecs::{default_archetypes::*, EntityArchetype, WorldBuilder, WorldBuilderSource, CommandBufferBuilderSource}, | ||||
|     render::{ | ||||
|         mesh::{Mesh, MeshType}, | ||||
|         pipeline::PipelineDescriptor, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson