entity archetypes

(for organization and compile time speedups)
This commit is contained in:
Carter Anderson 2020-01-18 15:36:24 -08:00
parent 7a386b8b46
commit e0753c8ace
4 changed files with 317 additions and 0 deletions

View file

@ -0,0 +1,191 @@
use bevy::prelude::*;
use bevy::ecs::*;
fn main() {
AppBuilder::new().add_defaults().setup_world(setup).run();
}
#[allow(dead_code)]
fn create_entities_insert_vec(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
// plane
world.insert(
(),
vec![(
plane_handle.clone(),
Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, 0.0),
)],
);
// cube
world.insert(
(),
vec![(
cube_handle,
Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, 1.0),
)],
);
// light
world.insert(
(),
vec![(
Light {
color: wgpu::Color {
r: 0.8,
g: 0.8,
b: 0.5,
a: 1.0,
},
fov: f32::to_radians(60.0),
depth: 0.1..50.0,
target_view: None,
},
LocalToWorld::identity(),
Translation::new(4.0, -4.0, 5.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0),
)],
);
// camera
world.insert(
(),
vec![(
Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}),
ActiveCamera,
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),
)),
)],
);
}
#[allow(dead_code)]
fn create_entities_builder_add_component(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
world.build()
// plane
.build_entity()
.add(plane_handle.clone())
.add(Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))))
.add(LocalToWorld::identity())
.add(Translation::new(0.0, 0.0, 0.0))
// cube
.build_entity()
.add(cube_handle)
.add(Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))))
.add(LocalToWorld::identity())
.add(Translation::new(0.0, 0.0, 1.0))
// light
.build_entity()
.add(Light {
color: wgpu::Color {
r: 0.8,
g: 0.8,
b: 0.5,
a: 1.0,
},
fov: f32::to_radians(60.0),
depth: 0.1..50.0,
target_view: None,
})
.add(LocalToWorld::identity())
.add(Translation::new(4.0, -4.0, 5.0))
.add(Rotation::from_euler_angles(0.0, 0.0, 0.0))
// camera
.build_entity()
.add(Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}))
.add(ActiveCamera)
.add(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),
)))
.build();
}
fn create_entities_builder_archetype(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
world.build()
// plane
.build_archetype(Object3dEntity {
mesh: plane_handle.clone(),
material: Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))),
local_to_world: LocalToWorld::identity(),
translation: Translation::new(0.0, 0.0, 0.0),
})
// cube
.build_archetype(Object3dEntity {
mesh: cube_handle,
material: Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))),
local_to_world: LocalToWorld::identity(),
translation: Translation::new(0.0, 0.0, 1.0),
})
// light
.build_archetype(LightEntity {
light: Light {
color: wgpu::Color {
r: 0.8,
g: 0.8,
b: 0.5,
a: 1.0,
},
fov: f32::to_radians(60.0),
depth: 0.1..50.0,
target_view: None,
},
local_to_world: LocalToWorld::identity(),
translation: Translation::new(4.0, -4.0, 5.0),
rotation: Rotation::from_euler_angles(0.0, 0.0, 0.0),
})
// camera
.build_archetype(CameraEntity {
camera: Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0,
near: 1.0,
far: 1000.0,
aspect_ratio: 1.0,
}),
active_camera: ActiveCamera,
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),
)),
})
.build();
}
fn setup(world: &mut World) {
let cube = Mesh::load(MeshType::Cube);
let plane = Mesh::load(MeshType::Plane { size: 10.0 });
let (cube_handle, plane_handle) = {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
(mesh_storage.add(cube), mesh_storage.add(plane))
};
// no-archetype precompile: 1.24 sec
// archetype precompile: 1.07 sec
// create_entities_insert_vec(world, plane_handle, cube_handle);
// no-archetype precompile: .93
// noarchetype precompile: .93
// create_entities_builder_add_component(world, plane_handle, cube_handle);
// archetype precompile: 0.65
create_entities_builder_archetype(world, plane_handle, cube_handle);
}

65
src/ecs/archetypes.rs Normal file
View file

@ -0,0 +1,65 @@
use crate::prelude::*;
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;
// add_components appears to be missing from World. it will be less efficient without that
// fn add_components(self, world: &mut World);
}
pub struct Object3dEntity {
pub mesh: Handle<Mesh>,
pub material: Material,
pub local_to_world: LocalToWorld,
pub translation: Translation,
}
// TODO: make this a macro
impl EntityArchetype for Object3dEntity {
fn insert(self, world: &mut World) -> Entity {
*world.insert((), vec![(
self.mesh,
self.material,
self.local_to_world,
self.translation,
)]).first().unwrap()
}
}
pub struct LightEntity {
pub light: Light,
pub local_to_world: LocalToWorld,
pub translation: Translation,
pub rotation: Rotation,
}
// TODO: make this a macro
impl EntityArchetype for LightEntity {
fn insert(self, world: &mut World) -> Entity {
*world.insert((), vec![(
self.light,
self.local_to_world,
self.translation,
self.rotation,
)]).first().unwrap()
}
}
pub struct CameraEntity {
pub camera: Camera,
pub active_camera: ActiveCamera,
pub local_to_world: LocalToWorld,
}
// TODO: make this a macro
impl EntityArchetype for CameraEntity {
fn insert(self, world: &mut World) -> Entity {
*world.insert((), vec![(
self.camera,
self.active_camera,
self.local_to_world,
)]).first().unwrap()
}
}

55
src/ecs/entity_builder.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::ecs::EntityArchetype;
use legion::prelude::*;
pub trait EntityBuilderSource {
fn build(&mut self) -> EntityBuilder;
}
impl EntityBuilderSource for World {
fn build(&mut self) -> EntityBuilder {
EntityBuilder {
world: self,
current_entity: None,
}
}
}
pub struct EntityBuilder<'a> {
world: &'a mut World,
current_entity: Option<Entity>,
}
impl<'a> EntityBuilder<'a> {
pub fn build_entity(mut self) -> Self {
let entity = *self.world.insert((), vec![()]).first().unwrap();
self.current_entity = Some(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
.world
.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
.world
.add_tag(*self.current_entity.as_ref().unwrap(), tag);
self
}
pub fn build_archetype(mut self, entity_archetype: impl EntityArchetype) -> Self {
self.current_entity = Some(entity_archetype.insert(self.world));
self
}
}

View file

@ -1,3 +1,9 @@
mod entity_builder;
mod archetypes;
pub use entity_builder::*;
pub use archetypes::*;
use crate::prelude::{Children, Entity, SubWorld, World};
pub fn run_on_hierarchy<T>(