mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
wander spawner
This commit is contained in:
parent
21ce87ba45
commit
816d0c9bdd
8 changed files with 279 additions and 73 deletions
|
@ -14,3 +14,4 @@ glsl-to-spirv = "0.1"
|
||||||
zerocopy = "0.2"
|
zerocopy = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
|
rand = "0.7.2"
|
|
@ -1,28 +1,149 @@
|
||||||
use bevy::*;
|
use bevy::*;
|
||||||
use bevy::{render::*, asset::{Asset, AssetStorage}, math};
|
use bevy::{render::*, asset::{Asset, AssetStorage, Handle}, math, Schedulable};
|
||||||
|
use rand::{rngs::StdRng, Rng, SeedableRng, random};
|
||||||
|
|
||||||
// fn build_move_system() -> Box<dyn Scheduleable> {
|
fn build_wander_system(world: &mut World) -> Box<dyn Schedulable> {
|
||||||
// SystemBuilder::new("MoveSystem")
|
let mut rng = StdRng::from_entropy();
|
||||||
// .with_query(<>)
|
|
||||||
// }
|
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.vector + direction * distance;
|
||||||
|
wander.elapsed = 0.0;
|
||||||
|
wander.duration = rng.gen_range(wander.duration_bounds.x, wander.duration_bounds.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_navigate_system(world: &mut World) -> Box<dyn Schedulable> {
|
||||||
|
SystemBuilder::new("Navigate")
|
||||||
|
.with_query(<(
|
||||||
|
Read<Person>,
|
||||||
|
Write<Translation>,
|
||||||
|
Write<Velocity>,
|
||||||
|
Write<NavigationPoint>,
|
||||||
|
)>::query())
|
||||||
|
.build(move |_, world, _, person_query| {
|
||||||
|
for (_, mut translation, mut velocity, mut navigation_point) in person_query.iter(world) {
|
||||||
|
let distance = navigation_point.target - translation.vector;
|
||||||
|
if math::length(&distance) > 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(world: &mut World) -> 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.vector += velocity.value * time.delta_seconds;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_print_status_system(world: &mut World) -> Box<dyn Schedulable> {
|
||||||
|
let mut elapsed = 0.0;
|
||||||
|
SystemBuilder::new("PrintStatus")
|
||||||
|
.read_resource::<Time>()
|
||||||
|
.with_query(<(
|
||||||
|
Read<Person>,
|
||||||
|
)>::query())
|
||||||
|
.build(move |_, world, time , person_query| {
|
||||||
|
elapsed += time.delta_seconds;
|
||||||
|
if elapsed > 1.0 {
|
||||||
|
println!("fps: {}", if time.delta_seconds == 0.0 { 0.0 } else { 1.0 / time.delta_seconds });
|
||||||
|
println!("peeps: {}", person_query.iter(world).count());
|
||||||
|
elapsed = 0.0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_spawner_system(world: &mut World) -> Box<dyn Schedulable> {
|
||||||
|
let mesh_handle = {
|
||||||
|
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
|
||||||
|
mesh_storage.get_named("cube").unwrap()
|
||||||
|
};
|
||||||
|
let mut elapsed = 0.0;
|
||||||
|
SystemBuilder::new("Spawner")
|
||||||
|
.read_resource::<Time>()
|
||||||
|
.with_query(<(
|
||||||
|
Read<Person>,
|
||||||
|
)>::query())
|
||||||
|
.build(move |command_buffer, world, time , person_query| {
|
||||||
|
elapsed += time.delta_seconds;
|
||||||
|
if elapsed > 0.5 {
|
||||||
|
for i in 0..20 {
|
||||||
|
spawn_person(command_buffer, mesh_handle.clone());
|
||||||
|
}
|
||||||
|
elapsed = 0.0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
let universe = Universe::new();
|
||||||
let mut world = universe.create_world();
|
let mut world = universe.create_world();
|
||||||
let mut scheduler = SystemScheduler::<ApplicationStage>::new();
|
let mut scheduler = SystemScheduler::<ApplicationStage>::new();
|
||||||
let transform_system_bundle = transform_system_bundle::build(&mut world);
|
|
||||||
scheduler.add_systems(ApplicationStage::Update, transform_system_bundle);
|
|
||||||
// Create a query which finds all `Position` and `Velocity` components
|
|
||||||
// let mut query = Read::<Transform>::query();
|
|
||||||
let cube = Mesh::load(MeshType::Cube);
|
let cube = Mesh::load(MeshType::Cube);
|
||||||
let plane = Mesh::load(MeshType::Plane{ size: 10 });
|
let plane = Mesh::load(MeshType::Plane{ size: 25 });
|
||||||
let mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
|
let mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
|
||||||
|
|
||||||
// this currently breaks because Arcs cant be modified after they are cloned :(
|
let mesh_handle = mesh_storage.add(cube, "cube");
|
||||||
let mesh_handle = mesh_storage.add(cube);
|
let plane_handle = mesh_storage.add(plane, "plane");
|
||||||
let plane_handle = mesh_storage.add(plane);
|
|
||||||
world.resources.insert(mesh_storage);
|
world.resources.insert(mesh_storage);
|
||||||
|
|
||||||
|
let transform_system_bundle = transform_system_bundle::build(&mut world);
|
||||||
|
scheduler.add_systems(ApplicationStage::Update, transform_system_bundle);
|
||||||
|
scheduler.add_system(ApplicationStage::Update, build_wander_system(&mut world));
|
||||||
|
scheduler.add_system(ApplicationStage::Update, build_navigate_system(&mut world));
|
||||||
|
scheduler.add_system(ApplicationStage::Update, build_move_system(&mut world));
|
||||||
|
scheduler.add_system(ApplicationStage::Update, build_spawner_system(&mut world));
|
||||||
|
scheduler.add_system(ApplicationStage::Update, build_print_status_system(&mut world));
|
||||||
|
|
||||||
world.insert((), vec![
|
world.insert((), vec![
|
||||||
// plane
|
// plane
|
||||||
(
|
(
|
||||||
|
@ -31,20 +152,8 @@ fn main() {
|
||||||
LocalToWorld::identity(),
|
LocalToWorld::identity(),
|
||||||
Translation::new(0.0, 0.0, 0.0)
|
Translation::new(0.0, 0.0, 0.0)
|
||||||
),
|
),
|
||||||
// cubes
|
|
||||||
(
|
|
||||||
Material::new(math::vec4(0.1, 0.1, 0.6, 1.0)),
|
|
||||||
mesh_handle.clone(),
|
|
||||||
LocalToWorld::identity(),
|
|
||||||
Translation::new(1.5, 0.0, 1.0)
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Material::new(math::vec4(0.6, 0.1, 0.1, 1.0)),
|
|
||||||
mesh_handle,
|
|
||||||
LocalToWorld::identity(),
|
|
||||||
Translation::new(-1.5, 0.0, 1.0)
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
world.insert((), vec![
|
world.insert((), vec![
|
||||||
// lights
|
// lights
|
||||||
(
|
(
|
||||||
|
@ -80,6 +189,7 @@ fn main() {
|
||||||
Translation::new(-5.0, 7.0, 10.0)
|
Translation::new(-5.0, 7.0, 10.0)
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
world.insert((), vec![
|
world.insert((), vec![
|
||||||
// camera
|
// camera
|
||||||
(
|
(
|
||||||
|
@ -90,7 +200,7 @@ fn main() {
|
||||||
aspect_ratio: 1.0,
|
aspect_ratio: 1.0,
|
||||||
}),
|
}),
|
||||||
LocalToWorld(math::look_at_rh(
|
LocalToWorld(math::look_at_rh(
|
||||||
&math::vec3(3.0, -10.0, 6.0),
|
&math::vec3(6.0, -40.0, 20.0),
|
||||||
&math::vec3(0.0, 0.0, 0.0),
|
&math::vec3(0.0, 0.0, 0.0),
|
||||||
&math::vec3(0.0, 0.0, 1.0),)),
|
&math::vec3(0.0, 0.0, 1.0),)),
|
||||||
// Translation::new(0.0, 0.0, 0.0),
|
// Translation::new(0.0, 0.0, 0.0),
|
||||||
|
@ -99,3 +209,28 @@ fn main() {
|
||||||
|
|
||||||
Application::run(universe, world, scheduler);
|
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),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
|
@ -9,11 +9,12 @@ use zerocopy::AsBytes;
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use wgpu::{Surface, Device, Queue, SwapChain, SwapChainDescriptor};
|
use wgpu::{Surface, Device, Queue, SwapChain, SwapChainDescriptor};
|
||||||
|
|
||||||
use crate::{vertex::*, render::*, math, LocalToWorld, ApplicationStage};
|
use crate::{vertex::*, render::*, math, LocalToWorld, ApplicationStage, Time};
|
||||||
|
|
||||||
pub struct Application
|
pub struct Application
|
||||||
{
|
{
|
||||||
|
@ -37,13 +38,13 @@ impl Application {
|
||||||
(Self::MAX_LIGHTS * mem::size_of::<LightRaw>()) as wgpu::BufferAddress;
|
(Self::MAX_LIGHTS * mem::size_of::<LightRaw>()) as wgpu::BufferAddress;
|
||||||
|
|
||||||
let local_bind_group_layout =
|
let local_bind_group_layout =
|
||||||
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
Rc::new(self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
bindings: &[wgpu::BindGroupLayoutBinding {
|
bindings: &[wgpu::BindGroupLayoutBinding {
|
||||||
binding: 0,
|
binding: 0,
|
||||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
|
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
|
||||||
}],
|
}],
|
||||||
});
|
}));
|
||||||
|
|
||||||
let light_uniform_buffer = Arc::new(UniformBuffer {
|
let light_uniform_buffer = Arc::new(UniformBuffer {
|
||||||
buffer: self.device.create_buffer(&wgpu::BufferDescriptor {
|
buffer: self.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
@ -55,29 +56,6 @@ impl Application {
|
||||||
size: light_uniform_size,
|
size: light_uniform_size,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut materials = <Write<Material>>::query();
|
|
||||||
for mut material in materials.iter(&mut self.world) {
|
|
||||||
let entity_uniform_size = mem::size_of::<MaterialUniforms>() as wgpu::BufferAddress;
|
|
||||||
let uniform_buf = self.device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
size: entity_uniform_size,
|
|
||||||
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
|
||||||
});
|
|
||||||
|
|
||||||
let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &local_bind_group_layout,
|
|
||||||
bindings: &[wgpu::Binding {
|
|
||||||
binding: 0,
|
|
||||||
resource: wgpu::BindingResource::Buffer {
|
|
||||||
buffer: &uniform_buf,
|
|
||||||
range: 0 .. entity_uniform_size,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
material.bind_group = Some(bind_group);
|
|
||||||
material.uniform_buf = Some(uniform_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
let light_count = <Read<Light>>::query().iter(&mut self.world).count();
|
let light_count = <Read<Light>>::query().iter(&mut self.world).count();
|
||||||
let forward_uniforms = ForwardUniforms {
|
let forward_uniforms = ForwardUniforms {
|
||||||
proj: math::Mat4::identity().into(),
|
proj: math::Mat4::identity().into(),
|
||||||
|
@ -103,12 +81,25 @@ impl Application {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
let shadow_pass = ShadowPass::new(&mut self.device, &mut self.world, light_uniform_buffer.clone(), vb_desc.clone(), &local_bind_group_layout, Self::MAX_LIGHTS as u32);
|
let shadow_pass = ShadowPass::new(&mut self.device, &mut self.world, light_uniform_buffer.clone(), vb_desc.clone(), local_bind_group_layout.clone(), Self::MAX_LIGHTS as u32);
|
||||||
let forward_pass = ForwardPass::new(&mut self.device, forward_uniforms, light_uniform_buffer.clone(), &shadow_pass, vb_desc, &local_bind_group_layout, &self.swap_chain_descriptor);
|
let forward_pass = ForwardPass::new(&mut self.device, forward_uniforms, light_uniform_buffer.clone(), &shadow_pass, vb_desc, &local_bind_group_layout, &self.swap_chain_descriptor);
|
||||||
self.render_passes.push(Box::new(shadow_pass));
|
self.render_passes.push(Box::new(shadow_pass));
|
||||||
self.render_passes.push(Box::new(forward_pass));
|
self.render_passes.push(Box::new(forward_pass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) {
|
||||||
|
{
|
||||||
|
let mut time = self.world.resources.get_mut::<Time>().unwrap();
|
||||||
|
time.start();
|
||||||
|
}
|
||||||
|
self.scheduler.execute(&mut self.world);
|
||||||
|
self.render();
|
||||||
|
{
|
||||||
|
let mut time = self.world.resources.get_mut::<Time>().unwrap();
|
||||||
|
time.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resize(&mut self, width: u32, height: u32)
|
fn resize(&mut self, width: u32, height: u32)
|
||||||
{
|
{
|
||||||
self.swap_chain_descriptor.width = width;
|
self.swap_chain_descriptor.width = width;
|
||||||
|
@ -137,7 +128,7 @@ impl Application {
|
||||||
self.queue.submit(&[command_buffer]);
|
self.queue.submit(&[command_buffer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: WindowEvent)
|
fn handle_event(&mut self, _: WindowEvent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +141,7 @@ impl Application {
|
||||||
let mut encoder =
|
let mut encoder =
|
||||||
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||||
|
|
||||||
let mut entities = <(Read<Material>, Read<LocalToWorld>)>::query();
|
let mut entities = <(Write<Material>, Read<LocalToWorld>)>::query();
|
||||||
let entities_count = entities.iter(&mut self.world).count();
|
let entities_count = entities.iter(&mut self.world).count();
|
||||||
let size = mem::size_of::<MaterialUniforms>();
|
let size = mem::size_of::<MaterialUniforms>();
|
||||||
let temp_buf_data = self.device
|
let temp_buf_data = self.device
|
||||||
|
@ -175,6 +166,11 @@ impl Application {
|
||||||
|
|
||||||
let temp_buf = temp_buf_data.finish();
|
let temp_buf = temp_buf_data.finish();
|
||||||
|
|
||||||
|
for pass in self.render_passes.iter_mut() {
|
||||||
|
pass.render(&mut self.device, &mut frame, &mut encoder, &mut self.world);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this should happen before rendering
|
||||||
for (i, (entity, _)) in entities.iter(&mut self.world).enumerate() {
|
for (i, (entity, _)) in entities.iter(&mut self.world).enumerate() {
|
||||||
encoder.copy_buffer_to_buffer(
|
encoder.copy_buffer_to_buffer(
|
||||||
&temp_buf,
|
&temp_buf,
|
||||||
|
@ -185,16 +181,12 @@ impl Application {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for pass in self.render_passes.iter_mut() {
|
|
||||||
pass.render(&mut self.device, &mut frame, &mut encoder, &mut self.world);
|
|
||||||
}
|
|
||||||
|
|
||||||
let command_buffer = encoder.finish();
|
let command_buffer = encoder.finish();
|
||||||
self.queue.submit(&[command_buffer]);
|
self.queue.submit(&[command_buffer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn run(universe: Universe, world: World, system_scheduler: SystemScheduler<ApplicationStage>) {
|
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...");
|
||||||
|
@ -217,6 +209,7 @@ impl Application {
|
||||||
let (window, hidpi_factor, size, surface) = {
|
let (window, hidpi_factor, 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((1920, 1080).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);
|
||||||
|
@ -232,6 +225,8 @@ 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 mut app = Application {
|
let mut app = Application {
|
||||||
universe,
|
universe,
|
||||||
|
@ -280,12 +275,11 @@ impl Application {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
app.update(event);
|
app.handle_event(event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
event::Event::EventsCleared => {
|
event::Event::EventsCleared => {
|
||||||
app.scheduler.execute(&mut app.world);
|
app.update();
|
||||||
app.render();
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{sync::{Arc, RwLock}, marker::PhantomData, ops::Drop};
|
use std::{sync::{Arc, RwLock}, marker::PhantomData, ops::Drop, collections::HashMap};
|
||||||
|
|
||||||
pub struct Handle<T>
|
pub struct Handle<T>
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@ pub trait Asset<D> {
|
||||||
pub struct AssetStorage<T, D> where T: Asset<D> {
|
pub struct AssetStorage<T, D> where T: Asset<D> {
|
||||||
assets: Vec<Option<T>>,
|
assets: Vec<Option<T>>,
|
||||||
free_indices: Arc<RwLock<Vec<usize>>>,
|
free_indices: Arc<RwLock<Vec<usize>>>,
|
||||||
|
names: HashMap<String, Arc<RwLock<usize>>>,
|
||||||
marker: PhantomData<D>,
|
marker: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,24 +44,43 @@ impl<T, D> AssetStorage<T, D> where T: Asset<D> {
|
||||||
AssetStorage {
|
AssetStorage {
|
||||||
assets: Vec::new(),
|
assets: Vec::new(),
|
||||||
free_indices: Arc::new(RwLock::new(Vec::new())),
|
free_indices: Arc::new(RwLock::new(Vec::new())),
|
||||||
|
names: HashMap::new(),
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, asset: T) -> Handle<T> {
|
pub fn get_named(&self, name: &str) -> Option<Handle<T>> {
|
||||||
|
match self.names.get(name) {
|
||||||
|
Some(id) => {
|
||||||
|
Some(Handle {
|
||||||
|
id: id.clone(),
|
||||||
|
marker: PhantomData,
|
||||||
|
free_indices: self.free_indices.clone()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, asset: T, name: &str) -> Handle<T> {
|
||||||
match self.free_indices.write().unwrap().pop() {
|
match self.free_indices.write().unwrap().pop() {
|
||||||
Some(id) => {
|
Some(id) => {
|
||||||
self.assets[id as usize] = Some(asset);
|
self.assets[id as usize] = Some(asset);
|
||||||
|
let handle = Arc::new(RwLock::new(id));
|
||||||
|
self.names.insert(name.to_string(), handle.clone());
|
||||||
Handle {
|
Handle {
|
||||||
id: Arc::new(RwLock::new(id)),
|
id: handle,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
free_indices: self.free_indices.clone()
|
free_indices: self.free_indices.clone()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
self.assets.push(Some(asset));
|
self.assets.push(Some(asset));
|
||||||
|
let id = self.assets.len() - 1;
|
||||||
|
let handle = Arc::new(RwLock::new(id));
|
||||||
|
self.names.insert(name.to_string(), handle.clone());
|
||||||
Handle {
|
Handle {
|
||||||
id: Arc::new(RwLock::new(self.assets.len() - 1)),
|
id: handle,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
free_indices: self.free_indices.clone()
|
free_indices: self.free_indices.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use legion::schedule::Stage;
|
use legion::schedule::Stage;
|
||||||
|
|
||||||
|
pub mod time;
|
||||||
|
pub use time::Time;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ApplicationStage {
|
pub enum ApplicationStage {
|
||||||
Update,
|
Update,
|
||||||
|
|
26
src/core/time.rs
Normal file
26
src/core/time.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
pub struct Time {
|
||||||
|
pub delta: Duration,
|
||||||
|
pub instant: Instant,
|
||||||
|
pub delta_seconds: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Time {
|
||||||
|
pub fn new() -> Time {
|
||||||
|
Time {
|
||||||
|
delta: Duration::from_secs(0),
|
||||||
|
instant: Instant::now(),
|
||||||
|
delta_seconds: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(&mut self) {
|
||||||
|
self.instant = Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
self.delta = Instant::now() - self.instant;
|
||||||
|
self.delta_seconds = self.delta.as_secs() as f32 + (self.delta.subsec_nanos() as f32 / 1.0e9);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use crate::{render::*, asset::*, LocalToWorld};
|
||||||
use wgpu::{BindGroupLayout, Buffer, CommandEncoder, Device, VertexBufferDescriptor, SwapChainOutput, SwapChainDescriptor};
|
use wgpu::{BindGroupLayout, Buffer, CommandEncoder, Device, VertexBufferDescriptor, SwapChainOutput, SwapChainDescriptor};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
use std::{mem, sync::Arc};
|
use std::{mem, sync::Arc, rc::Rc};
|
||||||
|
|
||||||
pub struct ShadowPass {
|
pub struct ShadowPass {
|
||||||
pub pipeline: wgpu::RenderPipeline,
|
pub pipeline: wgpu::RenderPipeline,
|
||||||
|
@ -11,6 +11,7 @@ pub struct ShadowPass {
|
||||||
pub shadow_texture: wgpu::Texture,
|
pub shadow_texture: wgpu::Texture,
|
||||||
pub shadow_view: wgpu::TextureView,
|
pub shadow_view: wgpu::TextureView,
|
||||||
pub shadow_sampler: wgpu::Sampler,
|
pub shadow_sampler: wgpu::Sampler,
|
||||||
|
pub local_bind_group_layout: Rc<BindGroupLayout>,
|
||||||
pub light_uniform_buffer: Arc::<UniformBuffer>,
|
pub light_uniform_buffer: Arc::<UniformBuffer>,
|
||||||
pub lights_are_dirty: bool,
|
pub lights_are_dirty: bool,
|
||||||
}
|
}
|
||||||
|
@ -47,6 +48,30 @@ impl Pass for ShadowPass {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for mut material in <Write<Material>>::query().iter(world) {
|
||||||
|
if let None = material.bind_group {
|
||||||
|
let entity_uniform_size = mem::size_of::<MaterialUniforms>() as wgpu::BufferAddress;
|
||||||
|
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
size: entity_uniform_size,
|
||||||
|
usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.local_bind_group_layout,
|
||||||
|
bindings: &[wgpu::Binding {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Buffer {
|
||||||
|
buffer: &uniform_buf,
|
||||||
|
range: 0 .. entity_uniform_size,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
material.bind_group = Some(bind_group);
|
||||||
|
material.uniform_buf = Some(uniform_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i, (mut light, _)) in <(Write<Light>, Read<LocalToWorld>)>::query().iter(world).enumerate() {
|
for (i, (mut light, _)) in <(Write<Light>, Read<LocalToWorld>)>::query().iter(world).enumerate() {
|
||||||
if let None = light.target_view {
|
if let None = light.target_view {
|
||||||
light.target_view = Some(self.shadow_texture.create_view(&wgpu::TextureViewDescriptor {
|
light.target_view = Some(self.shadow_texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
@ -114,7 +139,7 @@ impl ShadowPass {
|
||||||
depth: 1,
|
depth: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn new(device: &Device, _: &World, light_uniform_buffer: Arc::<UniformBuffer>, vertex_buffer_descriptor: VertexBufferDescriptor, local_bind_group_layout: &BindGroupLayout, max_lights: u32) -> ShadowPass {
|
pub fn new(device: &Device, _: &World, light_uniform_buffer: Arc::<UniformBuffer>, vertex_buffer_descriptor: VertexBufferDescriptor, local_bind_group_layout: Rc<BindGroupLayout>, max_lights: u32) -> ShadowPass {
|
||||||
// Create pipeline layout
|
// Create pipeline layout
|
||||||
let bind_group_layout =
|
let bind_group_layout =
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
@ -222,6 +247,7 @@ impl ShadowPass {
|
||||||
shadow_view,
|
shadow_view,
|
||||||
shadow_sampler,
|
shadow_sampler,
|
||||||
light_uniform_buffer,
|
light_uniform_buffer,
|
||||||
|
local_bind_group_layout,
|
||||||
lights_are_dirty: true,
|
lights_are_dirty: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# run using one of these commands
|
# run using one of these commands
|
||||||
# lld linker makes compiles faster
|
# lld linker makes compiles faster
|
||||||
# rust backtrace gives you a nice backtrace on panics
|
# rust backtrace gives you a nice backtrace on panics
|
||||||
|
# -Zshare-generics=y makes generics slightly faster for some reason
|
||||||
env RUSTFLAGS="-C link-arg=-fuse-ld=lld" cargo run --release
|
env RUSTFLAGS="-C link-arg=-fuse-ld=lld" cargo run --release
|
||||||
env RUSTFLAGS="-C link-arg=-fuse-ld=lld" RUST_BACKTRACE=1 cargo run --release
|
env RUSTFLAGS="-C link-arg=-fuse-ld=lld -Zshare-generics=y" RUST_BACKTRACE=1 cargo run --release
|
||||||
```
|
```
|
Loading…
Reference in a new issue