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