refactor app startup. AppBuilder. clean up examples

This commit is contained in:
Carter Anderson 2020-01-11 01:46:51 -08:00
parent aeeb85b7b0
commit 55c50f7185
16 changed files with 633 additions and 422 deletions

7
examples/empty.rs Normal file
View file

@ -0,0 +1,7 @@
use bevy::*;
fn main() {
AppBuilder::new()
.add_defaults()
.run();
}

212
examples/instancing.rs Normal file
View file

@ -0,0 +1,212 @@
use bevy::*;
use bevy::{render::*, asset::{Asset, AssetStorage, Handle}, math::{Mat4, Vec3}, Schedulable};
use rand::{rngs::StdRng, Rng, SeedableRng, random};
use std::collections::VecDeque;
struct Person;
struct Velocity {
pub value: math::Vec3,
}
struct NavigationPoint {
pub target: math::Vec3,
}
struct Wander {
pub duration_bounds: math::Vec2,
pub distance_bounds: math::Vec2,
pub duration: f32,
pub elapsed: f32,
}
fn main() {
AppBuilder::new()
.add_defaults()
.setup(&setup)
.run();
}
fn setup(world: &mut World, scheduler: &mut SystemScheduler<AppStage>) {
let cube = Mesh::load(MeshType::Cube);
let cube_handle = {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
mesh_storage.add(cube, "cube")
};
let transform_system_bundle = transform_system_bundle::build(world);
scheduler.add_systems(AppStage::Update, transform_system_bundle);
scheduler.add_system(AppStage::Update, build_wander_system());
scheduler.add_system(AppStage::Update, build_navigate_system());
scheduler.add_system(AppStage::Update, build_move_system());
scheduler.add_system(AppStage::Update, build_print_status_system());
world.insert((), vec![
// lights
(
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,
},
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
LocalToWorld::identity(),
Translation::new(4.0, -4.0, 5.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0)
),
]);
world.insert((), vec![
// camera
(
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(6.0, -40.0, 20.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),)),
)
]);
let mut rng = StdRng::from_entropy();
for _ in 0 .. 70000 {
create_person(world, cube_handle.clone(),
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)));
}
}
fn build_wander_system() -> Box<dyn Schedulable> {
let mut rng = StdRng::from_entropy();
SystemBuilder::new("Wander")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
Read<Translation>,
Write<Wander>,
Write<NavigationPoint>,
)>::query())
.build(move |
_, world,
time ,
person_query| {
for (_, translation, mut wander, mut navigation_point) in person_query.iter(world) {
wander.elapsed += time.delta_seconds;
if wander.elapsed >= wander.duration {
let direction = math::vec3(
rng.gen_range(-1.0, 1.0),
rng.gen_range(-1.0, 1.0),
rng.gen_range(0.0, 0.001),
).normalize();
let distance = rng.gen_range(wander.distance_bounds.x(), wander.distance_bounds.y());
navigation_point.target = translation.0 + direction * distance;
wander.elapsed = 0.0;
wander.duration = rng.gen_range(wander.duration_bounds.x(), wander.duration_bounds.y());
}
}
})
}
fn build_navigate_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Navigate")
.with_query(<(
Read<Person>,
Write<Translation>,
Write<Velocity>,
Write<NavigationPoint>,
)>::query())
.build(move |
_, world,
_, person_query| {
for (_, translation, mut velocity, navigation_point) in person_query.iter(world) {
let distance = navigation_point.target - translation.0;
if distance.length() > 0.01 {
let direction = distance.normalize();
velocity.value = direction * 2.0;
} else {
velocity.value = math::vec3(0.0, 0.0, 0.0);
}
}
})
}
fn build_move_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Move")
.read_resource::<Time>()
.with_query(<(
Write<Translation>,
Read<Velocity>,
)>::query())
.build(move |_, world, time , person_query| {
for (mut translation, velocity) in person_query.iter(world) {
translation.0 += velocity.value * time.delta_seconds;
}
})
}
fn build_print_status_system() -> Box<dyn Schedulable> {
let mut elapsed = 0.0;
let mut frame_time_total = 0.0;
let mut frame_time_count = 0;
let frame_time_max = 10;
let mut frame_time_values = VecDeque::new();
SystemBuilder::new("PrintStatus")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
)>::query())
.build(move |_, world, time , person_query| {
elapsed += time.delta_seconds;
frame_time_values.push_front(time.delta_seconds);
frame_time_total += time.delta_seconds;
frame_time_count += 1;
if frame_time_count > frame_time_max {
frame_time_count = frame_time_max;
frame_time_total -= frame_time_values.pop_back().unwrap();
}
if elapsed > 1.0 {
// println!("fps: {}", if time.delta_seconds == 0.0 { 0.0 } else { 1.0 / time.delta_seconds });
if frame_time_count > 0 && frame_time_total > 0.0 {
println!("fps: {}", 1.0 / (frame_time_total / frame_time_count as f32))
}
println!("peeps: {}", person_query.iter(world).count());
elapsed = 0.0;
}
})
}
fn create_person(world: &mut World, mesh_handle: Handle<Mesh>, translation: Translation) {
world.insert((), vec![
(
Person{},
Wander {
duration_bounds: math::vec2(3.0, 10.0),
distance_bounds: math::vec2(-50.0, 50.0),
elapsed: 0.0,
duration: 0.0,
},
NavigationPoint {
target: math::vec3(0.0, 0.0, 0.0),
},
Velocity {
value: math::vec3(0.0, 0.0, 0.0),
},
Instanced,
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()),
mesh_handle,
LocalToWorld::identity(),
translation
),
]);
}

View file

@ -1,11 +1,8 @@
use bevy::*; use bevy::*;
fn main() { fn main() {
// let universe = Universe::new();
// let world = universe.create_world();
// let scheduler = SystemScheduler::<ApplicationStage>::new();
// asset::load_gltf(get_path("examples/assets/Box.gltf").to_str().unwrap()).unwrap();
asset::load_gltf("examples/assets/Box.gltf").unwrap(); asset::load_gltf("examples/assets/Box.gltf").unwrap();
AppBuilder::new()
// Application::run(universe, world, scheduler); .add_defaults()
.run();
} }

110
examples/parenting.rs Normal file
View file

@ -0,0 +1,110 @@
use bevy::{*, render::*, asset::{Asset, AssetStorage}, math::{Mat4, Quat, Vec3}, Schedulable, Parent};
struct Rotator;
fn main() {
AppBuilder::new()
.add_defaults()
.setup(&setup)
.run();
}
fn build_rotator_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Rotator")
.read_resource::<Time>()
.with_query(<(
Write<Rotator>,
Write<Rotation>,
)>::query())
.build(move |_, world, time , light_query| {
for (_, mut rotation) in light_query.iter(world) {
rotation.0 = rotation.0 * Quat::from_rotation_x(3.0 * time.delta_seconds);
}
})
}
fn setup(world: &mut World, scheduler: &mut SystemScheduler<AppStage>) {
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, MeshType>>().unwrap();
(mesh_storage.add(cube, "cube"), mesh_storage.add(plane, "plane"))
};
let transform_system_bundle = transform_system_bundle::build(world);
scheduler.add_systems(AppStage::Update, transform_system_bundle);
scheduler.add_system(AppStage::Update, build_rotator_system());
// plane
world.insert((), vec![
(
plane_handle.clone(),
Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, -5.0)
),
]);
// cube
let parent_cube = *world.insert((), vec![
(
cube_handle.clone(),
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, 1.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0),
Rotator,
)
]).first().unwrap();
// cube
world.insert((), vec![
(
cube_handle,
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, 3.0),
Parent(parent_cube),
LocalToParent::identity(),
)
]);
// 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,
},
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
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, -15.0, 8.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),)),
)
]);
}

View file

@ -1,200 +1,46 @@
use bevy::*; use bevy::{*, render::*, asset::{Asset, AssetStorage}, math::{Mat4, Vec3}};
use bevy::{render::*, asset::{Asset, AssetStorage, Handle}, math::{Mat4, Quat, Vec3}, Schedulable, Parent};
use rand::{rngs::StdRng, Rng, SeedableRng, random};
use std::collections::VecDeque;
fn build_wander_system() -> Box<dyn Schedulable> {
let mut rng = StdRng::from_entropy();
SystemBuilder::new("Wander")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
Read<Translation>,
Write<Wander>,
Write<NavigationPoint>,
)>::query())
.build(move |
_, world,
time ,
person_query| {
for (_, translation, mut wander, mut navigation_point) in person_query.iter(world) {
wander.elapsed += time.delta_seconds;
if wander.elapsed >= wander.duration {
let direction = math::vec3(
rng.gen_range(-1.0, 1.0),
rng.gen_range(-1.0, 1.0),
rng.gen_range(0.0, 0.001),
).normalize();
let distance = rng.gen_range(wander.distance_bounds.x(), wander.distance_bounds.y());
navigation_point.target = translation.0 + direction * distance;
wander.elapsed = 0.0;
wander.duration = rng.gen_range(wander.duration_bounds.x(), wander.duration_bounds.y());
}
}
})
}
fn build_navigate_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Navigate")
.with_query(<(
Read<Person>,
Write<Translation>,
Write<Velocity>,
Write<NavigationPoint>,
)>::query())
.build(move |
_, world,
_, person_query| {
for (_, translation, mut velocity, navigation_point) in person_query.iter(world) {
let distance = navigation_point.target - translation.0;
if distance.length() > 0.01 {
let direction = distance.normalize();
velocity.value = direction * 2.0;
} else {
velocity.value = math::vec3(0.0, 0.0, 0.0);
}
}
})
}
fn build_move_system() -> Box<dyn Schedulable> {
SystemBuilder::new("Move")
.read_resource::<Time>()
.with_query(<(
Write<Translation>,
Read<Velocity>,
)>::query())
.build(move |_, world, time , person_query| {
for (mut translation, velocity) in person_query.iter(world) {
translation.0 += velocity.value * time.delta_seconds;
}
})
}
fn build_print_status_system() -> Box<dyn Schedulable> {
let mut elapsed = 0.0;
let mut frame_time_total = 0.0;
let mut frame_time_count = 0;
let frame_time_max = 10;
let mut frame_time_values = VecDeque::new();
SystemBuilder::new("PrintStatus")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
)>::query())
.build(move |_, world, time , person_query| {
elapsed += time.delta_seconds;
frame_time_values.push_front(time.delta_seconds);
frame_time_total += time.delta_seconds;
frame_time_count += 1;
if frame_time_count > frame_time_max {
frame_time_count = frame_time_max;
frame_time_total -= frame_time_values.pop_back().unwrap();
}
if elapsed > 1.0 {
// println!("fps: {}", if time.delta_seconds == 0.0 { 0.0 } else { 1.0 / time.delta_seconds });
if frame_time_count > 0 && frame_time_total > 0.0 {
println!("fps: {}", 1.0 / (frame_time_total / frame_time_count as f32))
}
println!("peeps: {}", person_query.iter(world).count());
elapsed = 0.0;
}
})
}
fn build_spawner_system(world: &mut World) -> Box<dyn Schedulable> {
let mesh_handle = {
let mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
mesh_storage.get_named("cube").unwrap()
};
let duration = 0.5;
let mut elapsed = duration;
let batch_size = 100;
SystemBuilder::new("Spawner")
.read_resource::<Time>()
.with_query(<(
Read<Person>,
)>::query())
.build(move |command_buffer, _, time , _| {
elapsed += time.delta_seconds;
if elapsed > duration {
for _ in 0..batch_size {
spawn_person(command_buffer, mesh_handle.clone());
}
elapsed = 0.0;
}
})
}
fn build_light_rotator_system() -> Box<dyn Schedulable> {
SystemBuilder::new("LightRotator")
.read_resource::<Time>()
.with_query(<(
Write<Light>,
Write<Rotation>,
)>::query())
.build(move |_, world, time , light_query| {
for (_, mut rotation) in light_query.iter(world) {
rotation.0 = rotation.0 * Quat::from_rotation_x(3.0 * time.delta_seconds);
}
})
}
struct Person {
}
struct Velocity {
pub value: math::Vec3,
}
struct NavigationPoint {
pub target: math::Vec3,
}
struct Wander {
pub duration_bounds: math::Vec2,
pub distance_bounds: math::Vec2,
pub duration: f32,
pub elapsed: f32,
}
fn main() { fn main() {
let universe = Universe::new(); AppBuilder::new()
let mut world = universe.create_world(); .add_defaults()
let mut scheduler = SystemScheduler::<ApplicationStage>::new(); .setup(&setup)
.run();
}
fn setup(world: &mut World, scheduler: &mut SystemScheduler<AppStage>) {
let cube = Mesh::load(MeshType::Cube); let cube = Mesh::load(MeshType::Cube);
let plane = Mesh::load(MeshType::Plane{ size: 24.5 }); let plane = Mesh::load(MeshType::Plane{ size: 10.0 });
let mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
let _cube_handle = mesh_storage.add(cube, "cube"); let (cube_handle, plane_handle) = {
let plane_handle = mesh_storage.add(plane, "plane"); let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
world.resources.insert(mesh_storage); (mesh_storage.add(cube, "cube"), mesh_storage.add(plane, "plane"))
};
let transform_system_bundle = transform_system_bundle::build(&mut world); let transform_system_bundle = transform_system_bundle::build(world);
scheduler.add_systems(ApplicationStage::Update, transform_system_bundle); scheduler.add_systems(AppStage::Update, transform_system_bundle);
scheduler.add_system(ApplicationStage::Update, build_wander_system());
scheduler.add_system(ApplicationStage::Update, build_navigate_system());
scheduler.add_system(ApplicationStage::Update, build_move_system());
// scheduler.add_system(ApplicationStage::Update, build_light_rotator_system());
// scheduler.add_system(ApplicationStage::Update, build_spawner_system(&mut world));
scheduler.add_system(ApplicationStage::Update, build_print_status_system());
// world.insert((), vec![ // plane
// // plane world.insert((), vec![
// ( (
// Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)), plane_handle.clone(),
// plane_handle.clone(), Material::new(math::vec4(0.1, 0.2, 0.1, 1.0)),
// LocalToWorld::identity(), LocalToWorld::identity(),
// Translation::new(0.0, 0.0, 0.0) Translation::new(0.0, 0.0, 0.0)
// ), ),
// ]); ]);
let x = *world.insert((), vec![ // cube
// lights world.insert((), vec![
(
cube_handle,
Material::new(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 { Light {
color: wgpu::Color { color: wgpu::Color {
@ -208,45 +54,14 @@ fn main() {
target_view: None, target_view: None,
}, },
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)), Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
// _cube_handle.clone(),
LocalToWorld::identity(), LocalToWorld::identity(),
Translation::new(4.0, -4.0, 5.0), Translation::new(4.0, -4.0, 5.0),
Rotation::from_euler_angles(0.0, 0.0, 0.0) Rotation::from_euler_angles(0.0, 0.0, 0.0)
), ),
// ( ]);
// Light {
// color: wgpu::Color {
// r: 1.0,
// g: 0.5,
// b: 0.5,
// a: 1.0,
// },
// fov: f32::to_radians(45.0),
// depth: 1.0 .. 20.0,
// target_view: None,
// },
// // Material::new(math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()),
// // cube_handle.clone(),
// LocalToWorld::identity(),
// Translation::new(-5.0, 7.0, 10.0)
// ),
]).first().unwrap();
// world.insert((), vec![
// (
// Material::new(math::vec4(1.0, 1.0, 1.0, 1.0)),
// _cube_handle.clone(),
// LocalToWorld::identity(),
// Translation::new(0.0, 0.0, 3.0),
// Scale(1.0),
// Parent(x),
// LocalToParent::identity(),
// )
// ]);
world.insert((), vec![
// camera // camera
world.insert((), vec![
( (
Camera::new(CameraType::Projection { Camera::new(CameraType::Projection {
fov: std::f32::consts::PI / 4.0, fov: std::f32::consts::PI / 4.0,
@ -256,114 +71,9 @@ fn main() {
}), }),
ActiveCamera, ActiveCamera,
LocalToWorld(Mat4::look_at_rh( LocalToWorld(Mat4::look_at_rh(
Vec3::new(6.0, -40.0, 20.0), Vec3::new(3.0, -8.0, 5.0),
Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),)), Vec3::new(0.0, 0.0, 1.0),)),
// Translation::new(0.0, 0.0, 0.0),
) )
]); ]);
world.insert((), vec![
// camera
(
Camera::new(CameraType::Orthographic {
left: 0.0,
right: 0.0,
bottom: 0.0,
top: 0.0,
near: 0.0,
far: 1.0,
}),
ActiveCamera2d,
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(75.0, 75.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 1.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(50.0, 50.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(1.0, 0.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(100.0, 100.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 0.0, 1.0, 1.0),
},
)
]);
let mut rng = StdRng::from_entropy();
for _ in 0 .. 5 {
create_person(&mut world, _cube_handle.clone(),
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)));
}
Application::run(universe, world, scheduler);
}
fn spawn_person(command_buffer: &mut CommandBuffer, mesh_handle: Handle<Mesh>) {
command_buffer.insert((), vec![
(
Person{},
Wander {
duration_bounds: math::vec2(3.0, 10.0),
distance_bounds: math::vec2(-50.0, 50.0),
elapsed: 0.0,
duration: 0.0,
},
NavigationPoint {
target: math::vec3(0.0, 0.0, 0.0),
},
Velocity {
value: math::vec3(0.0, 0.0, 0.0),
},
Instanced,
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()),
mesh_handle.clone(),
LocalToWorld::identity(),
Translation::new(0.0, 0.0, 1.0)
),
]);
}
fn create_person(world: &mut World, mesh_handle: Handle<Mesh>, translation: Translation) {
world.insert((), vec![
(
Person{},
Wander {
duration_bounds: math::vec2(3.0, 10.0),
distance_bounds: math::vec2(-50.0, 50.0),
elapsed: 0.0,
duration: 0.0,
},
NavigationPoint {
target: math::vec3(0.0, 0.0, 0.0),
},
Velocity {
value: math::vec3(0.0, 0.0, 0.0),
},
Instanced,
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>()),
mesh_handle,
LocalToWorld::identity(),
translation
),
]);
} }

108
examples/ui.rs Normal file
View file

@ -0,0 +1,108 @@
use bevy::{*, render::*, asset::{Asset, AssetStorage}, math::{Mat4, Vec3}};
fn main() {
AppBuilder::new()
.add_defaults()
.setup(&setup)
.run();
}
fn setup(world: &mut World, scheduler: &mut SystemScheduler<AppStage>) {
let cube = Mesh::load(MeshType::Cube);
let cube_handle = {
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
mesh_storage.add(cube, "cube")
};
let transform_system_bundle = transform_system_bundle::build(world);
scheduler.add_systems(AppStage::Update, transform_system_bundle);
world.insert((), vec![
(
cube_handle,
LocalToWorld::identity(),
Material::new(math::vec4(0.5, 0.3, 0.3, 1.0)),
)
]);
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)
),
]);
world.insert((), vec![
// camera
(
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, -5.0, 3.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),)),
)
]);
world.insert((), vec![
// camera
(
Camera::new(CameraType::Orthographic {
left: 0.0,
right: 0.0,
bottom: 0.0,
top: 0.0,
near: 0.0,
far: 1.0,
}),
ActiveCamera2d,
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(75.0, 75.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 1.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(50.0, 50.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(1.0, 0.0, 0.0, 1.0),
},
)
]);
world.insert((), vec![
(
Rect {
position: math::vec2(100.0, 100.0),
dimensions: math::vec2(100.0, 100.0),
color: math::vec4(0.0, 0.0, 1.0, 1.0),
},
)
]);
}

55
src/app/app_builder.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::{App, asset::AssetStorage, legion::prelude::{World, SystemScheduler}, render::{*, passes::*}, AppStage, Time};
pub struct AppBuilder {
pub app: App,
}
impl AppBuilder {
pub fn new() -> Self {
let world = World::new();
let scheduler = SystemScheduler::<AppStage>::new();
AppBuilder {
app: App::new(world, scheduler),
}
}
pub fn build(self) -> App {
self.app
}
pub fn run(self) {
self.app.run();
}
pub fn setup(mut self, setup: &dyn Fn(&mut World, &mut SystemScheduler<AppStage>)) -> Self {
setup(&mut self.app.world, &mut self.app.scheduler);
self
}
pub fn add_default_passes(mut self) -> Self {
self.app.render_graph.add_render_resource_manager(Box::new(render_resources::MaterialResourceManager));
self.app.render_graph.add_render_resource_manager(Box::new(render_resources::LightResourceManager::new(10)));
self.app.render_graph.add_render_resource_manager(Box::new(render_resources::GlobalResourceManager));
self.app.render_graph.add_render_resource_manager(Box::new(render_resources::Global2dResourceManager));
let depth_format = wgpu::TextureFormat::Depth32Float;
self.app.render_graph.set_pass("forward", Box::new(ForwardPass::new(depth_format)));
self.app.render_graph.set_pipeline("forward", "forward", Box::new(ForwardPipeline::new()));
self.app.render_graph.set_pipeline("forward", "forward_instanced", Box::new(ForwardInstancedPipeline::new(depth_format)));
self.app.render_graph.set_pipeline("forward", "ui", Box::new(UiPipeline::new()));
self
}
pub fn add_default_resources(mut self) -> Self {
self.app.world.resources.insert(Time::new());
self.app.world.resources.insert(AssetStorage::<Mesh, MeshType>::new());
self
}
pub fn add_defaults(self) -> Self {
self
.add_default_resources()
.add_default_passes()
}
}

18
src/app/app_stage.rs Normal file
View file

@ -0,0 +1,18 @@
use legion::schedule::Stage;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum AppStage {
Update,
Render,
}
impl Stage for AppStage {}
impl std::fmt::Display for AppStage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AppStage::Update => write!(f, "update"),
AppStage::Render => write!(f, "draw"),
}
}
}

View file

@ -1,3 +1,9 @@
mod app_stage;
mod app_builder;
pub use app_stage::AppStage;
pub use app_builder::AppBuilder;
use winit::{ use winit::{
event, event,
event::WindowEvent, event::WindowEvent,
@ -7,29 +13,26 @@ use winit::{
use legion::prelude::*; use legion::prelude::*;
use crate::{render::*, render::passes::*, ApplicationStage, Time}; use crate::{render::*, Time};
pub struct Application pub struct App
{ {
pub universe: Universe,
pub world: World, pub world: World,
pub window: Window, pub window: Option<Window>,
pub render_graph: RenderGraph, pub render_graph: RenderGraph,
pub scheduler: SystemScheduler<ApplicationStage>, pub swap_chain: Option<wgpu::SwapChain>,
pub scheduler: SystemScheduler<AppStage>,
} }
impl Application { impl App {
fn add_default_passes(&mut self) { pub fn new(world: World, scheduler: SystemScheduler<AppStage>) -> App {
self.render_graph.add_render_resource_manager(Box::new(render_resources::MaterialResourceManager)); App {
self.render_graph.add_render_resource_manager(Box::new(render_resources::LightResourceManager::new(10))); world: world,
self.render_graph.add_render_resource_manager(Box::new(render_resources::GlobalResourceManager)); scheduler: scheduler,
self.render_graph.add_render_resource_manager(Box::new(render_resources::Global2dResourceManager)); render_graph: RenderGraph::new(),
swap_chain: None,
let depth_format = wgpu::TextureFormat::Depth32Float; window: None,
self.render_graph.set_pass("forward", Box::new(ForwardPass::new(depth_format))); }
self.render_graph.set_pipeline("forward", "forward", Box::new(ForwardPipeline::new()));
self.render_graph.set_pipeline("forward", "forward_instanced", Box::new(ForwardInstancedPipeline::new(depth_format)));
self.render_graph.set_pipeline("forward", "ui", Box::new(UiPipeline::new()));
} }
fn update(&mut self) { fn update(&mut self) {
@ -47,7 +50,7 @@ impl Application {
fn resize(&mut self, width: u32, height: u32) fn resize(&mut self, width: u32, height: u32)
{ {
self.render_graph.resize(width, height, &mut self.world); self.swap_chain = Some(self.render_graph.resize(width, height, &mut self.world));
} }
fn handle_event(&mut self, _: WindowEvent) fn handle_event(&mut self, _: WindowEvent)
@ -56,11 +59,10 @@ impl Application {
fn render(&mut self) fn render(&mut self)
{ {
self.render_graph.render(&mut self.world); self.render_graph.render(&mut self.world, self.swap_chain.as_mut().unwrap());
} }
#[allow(dead_code)] pub fn run(mut self) {
pub fn run(universe: Universe, mut world: World, system_scheduler: SystemScheduler<ApplicationStage>) {
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
log::info!("Initializing the window..."); log::info!("Initializing the window...");
@ -80,14 +82,14 @@ impl Application {
limits: wgpu::Limits::default(), limits: wgpu::Limits::default(),
}); });
let (window, hidpi_factor, size, surface) = { let (window, size, surface) = {
let window = winit::window::Window::new(&event_loop).unwrap(); let window = winit::window::Window::new(&event_loop).unwrap();
window.set_title("bevy"); window.set_title("bevy");
window.set_inner_size((1280, 720).into()); window.set_inner_size((1280, 720).into());
let hidpi_factor = window.hidpi_factor(); let hidpi_factor = window.hidpi_factor();
let size = window.inner_size().to_physical(hidpi_factor); let size = window.inner_size().to_physical(hidpi_factor);
let surface = wgpu::Surface::create(&window); let surface = wgpu::Surface::create(&window);
(window, hidpi_factor, size, surface) (window, size, surface)
}; };
let swap_chain_descriptor = wgpu::SwapChainDescriptor { let swap_chain_descriptor = wgpu::SwapChainDescriptor {
@ -99,20 +101,11 @@ impl Application {
}; };
let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor); let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor);
world.resources.insert(Time::new());
log::info!("Initializing the example..."); log::info!("Initializing the example...");
let render_graph = RenderGraph::new(device, swap_chain_descriptor, swap_chain, queue, surface); self.render_graph.initialize(&mut self.world, device, swap_chain_descriptor, queue, surface);
let mut app = Application { self.window = Some(window);
universe, self.swap_chain = Some(swap_chain);
world,
window,
render_graph,
scheduler: system_scheduler,
};
app.add_default_passes();
app.render_graph.initialize(&mut app.world);
log::info!("Entering render loop..."); log::info!("Entering render loop...");
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
@ -126,11 +119,12 @@ impl Application {
event: WindowEvent::Resized(size), event: WindowEvent::Resized(size),
.. ..
} => { } => {
let hidpi_factor = self.window.as_ref().unwrap().hidpi_factor();
let physical = size.to_physical(hidpi_factor); let physical = size.to_physical(hidpi_factor);
log::info!("Resizing to {:?}", physical); log::info!("Resizing to {:?}", physical);
let width = physical.width.round() as u32; let width = physical.width.round() as u32;
let height = physical.height.round() as u32; let height = physical.height.round() as u32;
app.resize(width, height); self.resize(width, height);
} }
event::Event::WindowEvent { event, .. } => match event { event::Event::WindowEvent { event, .. } => match event {
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
@ -146,11 +140,11 @@ impl Application {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
_ => { _ => {
app.handle_event(event); self.handle_event(event);
} }
}, },
event::Event::EventsCleared => { event::Event::EventsCleared => {
app.update(); self.update();
} }
_ => (), _ => (),
} }

View file

@ -1,21 +1,2 @@
use legion::schedule::Stage;
pub mod time; pub mod time;
pub use time::Time; pub use time::Time;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ApplicationStage {
Update,
Render,
}
impl Stage for ApplicationStage {}
impl std::fmt::Display for ApplicationStage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ApplicationStage::Update => write!(f, "update"),
ApplicationStage::Render => write!(f, "draw"),
}
}
}

View file

@ -1,10 +1,10 @@
pub mod render; pub mod render;
pub mod asset; pub mod asset;
mod application; mod app;
mod vertex; mod vertex;
mod core; mod core;
pub use application::Application; pub use app::{App, AppStage, AppBuilder};
pub use crate::core::*; pub use crate::core::*;
pub use wgpu; pub use wgpu;

View file

@ -24,6 +24,10 @@ impl ForwardInstancedPipeline {
fn create_instance_buffer_infos(device: &Device, world: &World) -> Vec<InstanceBufferInfo> { fn create_instance_buffer_infos(device: &Device, world: &World) -> Vec<InstanceBufferInfo> {
let mut entities = <(Read<Material>, Read<LocalToWorld>, Read<Handle<Mesh>>, Read<Instanced>)>::query(); let mut entities = <(Read<Material>, Read<LocalToWorld>, Read<Handle<Mesh>>, Read<Instanced>)>::query();
let entities_count = entities.iter_immutable(world).count(); let entities_count = entities.iter_immutable(world).count();
if entities_count == 0 {
return Vec::new();
}
let size = mem::size_of::<SimpleMaterialUniforms>(); let size = mem::size_of::<SimpleMaterialUniforms>();
// TODO: use a staging buffer for more efficient gpu reads // TODO: use a staging buffer for more efficient gpu reads

View file

@ -33,6 +33,10 @@ impl UiPipeline {
let mut rect_query = <Read<Rect>>::query(); let mut rect_query = <Read<Rect>>::query();
let rect_count = rect_query.iter_immutable(world).count(); let rect_count = rect_query.iter_immutable(world).count();
if rect_count == 0 {
return Vec::new();
}
let mut data = Vec::with_capacity(rect_count); let mut data = Vec::with_capacity(rect_count);
// TODO: this probably isn't the best way to handle z-ordering // TODO: this probably isn't the best way to handle z-ordering
let mut z = 0.9999; let mut z = 0.9999;

View file

@ -11,12 +11,11 @@ use std::collections::HashMap;
use legion::world::World; use legion::world::World;
pub struct RenderGraph { pub struct RenderGraph {
pub data: RenderGraphData, pub data: Option<RenderGraphData>,
passes: HashMap<String, Box<dyn Pass>>, passes: HashMap<String, Box<dyn Pass>>,
pipelines: HashMap<String, Box<dyn Pipeline>>, pipelines: HashMap<String, Box<dyn Pipeline>>,
pass_pipelines: HashMap<String, Vec<String>>, pass_pipelines: HashMap<String, Vec<String>>,
render_resource_managers: Vec<Box<dyn RenderResourceManager>>, render_resource_managers: Vec<Box<dyn RenderResourceManager>>,
pub swap_chain: wgpu::SwapChain, // TODO: this is weird
} }
pub struct RenderGraphData { pub struct RenderGraphData {
@ -77,53 +76,56 @@ impl RenderGraphData {
} }
impl RenderGraph { impl RenderGraph {
pub fn new(device: wgpu::Device, swap_chain_descriptor: wgpu::SwapChainDescriptor, swap_chain: wgpu::SwapChain, queue: wgpu::Queue, surface: wgpu::Surface) -> Self { pub fn new() -> Self {
RenderGraph { RenderGraph {
passes: HashMap::new(), passes: HashMap::new(),
pipelines: HashMap::new(), pipelines: HashMap::new(),
swap_chain,
pass_pipelines: HashMap::new(), pass_pipelines: HashMap::new(),
render_resource_managers: Vec::new(), render_resource_managers: Vec::new(),
data: RenderGraphData::new(device, swap_chain_descriptor, queue, surface), data: None,
} }
} }
pub fn initialize(&mut self, world: &mut World) { pub fn initialize(&mut self, world: &mut World, device: wgpu::Device, swap_chain_descriptor: wgpu::SwapChainDescriptor, queue: wgpu::Queue, surface: wgpu::Surface) {
let mut data = RenderGraphData::new(device, swap_chain_descriptor, queue, surface);
for render_resource_manager in self.render_resource_managers.iter_mut() { for render_resource_manager in self.render_resource_managers.iter_mut() {
render_resource_manager.initialize(&mut self.data, world); render_resource_manager.initialize(&mut data, world);
} }
for pass in self.passes.values_mut() { for pass in self.passes.values_mut() {
pass.initialize(&mut self.data); pass.initialize(&mut data);
} }
for pipeline in self.pipelines.values_mut() { for pipeline in self.pipelines.values_mut() {
pipeline.initialize(&mut self.data, world); pipeline.initialize(&mut data, world);
}
} }
pub fn render(&mut self, world: &mut World) { self.data = Some(data);
let frame = self.swap_chain }
pub fn render(&mut self, world: &mut World, swap_chain: &mut wgpu::SwapChain) {
let frame = swap_chain
.get_next_texture() .get_next_texture()
.expect("Timeout when acquiring next swap chain texture"); .expect("Timeout when acquiring next swap chain texture");
let data = self.data.as_mut().unwrap();
let mut encoder = let mut encoder =
self.data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
for render_resource_manager in self.render_resource_managers.iter_mut() { for render_resource_manager in self.render_resource_managers.iter_mut() {
render_resource_manager.update(&mut self.data, &mut encoder, world); render_resource_manager.update(data, &mut encoder, world);
} }
for (pass_name, pass) in self.passes.iter_mut() { for (pass_name, pass) in self.passes.iter_mut() {
loop { loop {
let render_pass = pass.begin(&mut self.data, world, &mut encoder, &frame); let render_pass = pass.begin(data, world, &mut encoder, &frame);
if let Some(mut render_pass) = render_pass { if let Some(mut render_pass) = render_pass {
// TODO: assign pipelines to specific passes // TODO: assign pipelines to specific passes
if let Some(pipeline_names) = self.pass_pipelines.get(pass_name) { if let Some(pipeline_names) = self.pass_pipelines.get(pass_name) {
for pipeline_name in pipeline_names.iter() { for pipeline_name in pipeline_names.iter() {
let pipeline = self.pipelines.get_mut(pipeline_name).unwrap(); let pipeline = self.pipelines.get_mut(pipeline_name).unwrap();
render_pass.set_pipeline(pipeline.get_pipeline()); render_pass.set_pipeline(pipeline.get_pipeline());
pipeline.render(&mut self.data, &mut render_pass, &frame, world); pipeline.render(data, &mut render_pass, &frame, world);
} }
} }
@ -135,32 +137,33 @@ impl RenderGraph {
} }
let command_buffer = encoder.finish(); let command_buffer = encoder.finish();
self.data.queue.submit(&[command_buffer]); data.queue.submit(&[command_buffer]);
} }
pub fn resize(&mut self, width: u32, height: u32, world: &mut World) { pub fn resize(&mut self, width: u32, height: u32, world: &mut World) -> wgpu::SwapChain {
self.data.swap_chain_descriptor.width = width; let data = self.data.as_mut().unwrap();
self.data.swap_chain_descriptor.height = height; data.swap_chain_descriptor.width = width;
self.swap_chain = self.data.device.create_swap_chain(&self.data.surface, &self.data.swap_chain_descriptor); data.swap_chain_descriptor.height = height;
let swap_chain = data.device.create_swap_chain(&data.surface, &data.swap_chain_descriptor);
let mut encoder = let mut encoder =
self.data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); data.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
for render_resource_manager in self.render_resource_managers.iter_mut() { for render_resource_manager in self.render_resource_managers.iter_mut() {
render_resource_manager.resize(&mut self.data, &mut encoder, world); render_resource_manager.resize(data, &mut encoder, world);
} }
let command_buffer = encoder.finish(); let command_buffer = encoder.finish();
for pass in self.passes.values_mut() { for pass in self.passes.values_mut() {
pass.resize(&mut self.data); pass.resize(data);
} }
for pipeline in self.pipelines.values_mut() { for pipeline in self.pipelines.values_mut() {
pipeline.resize(&mut self.data); pipeline.resize(data);
} }
self.data.queue.submit(&[command_buffer]); data.queue.submit(&[command_buffer]);
swap_chain
} }
pub fn add_render_resource_manager(&mut self, render_resource_manager: Box<dyn RenderResourceManager>) { pub fn add_render_resource_manager(&mut self, render_resource_manager: Box<dyn RenderResourceManager>) {

View file

@ -42,6 +42,10 @@ impl RenderResourceManager for LightResourceManager {
let mut light_query = <(Read<Light>, Read<LocalToWorld>, Read<Translation>)>::query(); let mut light_query = <(Read<Light>, Read<LocalToWorld>, Read<Translation>)>::query();
let light_count = light_query.iter(world).count(); let light_count = light_query.iter(world).count();
if light_count == 0 {
return;
}
self.lights_are_dirty = false; self.lights_are_dirty = false;
let size = mem::size_of::<LightRaw>(); let size = mem::size_of::<LightRaw>();
let total_size = size * light_count; let total_size = size * light_count;

View file

@ -26,6 +26,10 @@ impl RenderResourceManager for MaterialResourceManager {
let mut entities = <(Write<Material>, Read<LocalToWorld>)>::query() let mut entities = <(Write<Material>, Read<LocalToWorld>)>::query()
.filter(!component::<Instanced>()); .filter(!component::<Instanced>());
let entities_count = entities.iter(world).count(); let entities_count = entities.iter(world).count();
if entities_count == 0 {
return;
}
let size = mem::size_of::<MaterialUniforms>(); let size = mem::size_of::<MaterialUniforms>();
let temp_buf_data = render_graph.device let temp_buf_data = render_graph.device
.create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC); .create_buffer_mapped(entities_count * size, wgpu::BufferUsage::COPY_SRC);