mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
Upgrade to Bevy v0.12 (#12)
* Migrate `System::pipe(...)` calls to `System::map(...)` * Migrate `EventReader::iter()` and `EventReader::into_iter()` calls to `EventReader::read()` * Migrate asset handling * Generate `*.meta` files for assets * Migrate a shader import * Fix emissive materials double-applying their emissive strength * Fix non-normalized bone weights resulting in incorrect vertex positions * Set shadow filtering to `Hardware2x2` to mitigate increase in shader compilation times
This commit is contained in:
@@ -85,7 +85,7 @@ fn camera_control_kinematic(
|
||||
let mut any_started = false;
|
||||
let mut any_stopped = false;
|
||||
|
||||
for action in input.iter().filter(|action| {
|
||||
for action in input.read().filter(|action| {
|
||||
!matches!(
|
||||
action,
|
||||
InputAction(_, Action::Camera(CameraMotion::Translate(_)))
|
||||
@@ -123,7 +123,7 @@ fn process_physical_inputs(
|
||||
q_camera: Query<(Entity, &Velocity), With<CameraController>>,
|
||||
mut q_interp: Query<&mut InterpVelocity>,
|
||||
) {
|
||||
for action in input.iter() {
|
||||
for action in input.read() {
|
||||
let &InputAction(_, Action::Camera(CameraMotion::Translate(delta))) = action else {
|
||||
continue;
|
||||
};
|
||||
@@ -162,7 +162,7 @@ fn process_focus_inputs(
|
||||
mut q_interp_pos: Query<&mut InterpPosition>,
|
||||
q_selected_xform: Query<&GlobalTransform, With<Selected>>,
|
||||
) {
|
||||
if input.iter().any(|action| {
|
||||
if input.read().any(|action| {
|
||||
matches!(
|
||||
action,
|
||||
InputAction(Lifecycle::Stop, Action::Selection(Selection::Focus))
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ impl Plugin for DebugPlugin {
|
||||
|
||||
fn toggle_debug_mode(mut input: EventReader<InputAction>, mut r_debug: ResMut<DebugMode>) {
|
||||
if input
|
||||
.iter()
|
||||
.read()
|
||||
.any(|action| matches!(action, InputAction(Lifecycle::Stop, Action::ToggleDebug)))
|
||||
{
|
||||
**r_debug = !**r_debug;
|
||||
|
||||
+2
-2
@@ -252,7 +252,7 @@ fn translate_fps_camera_events(
|
||||
}
|
||||
|
||||
// Wheel zoom
|
||||
for &MouseWheel { y, .. } in mouse_wheel.iter() {
|
||||
for &MouseWheel { y, .. } in mouse_wheel.read() {
|
||||
// info!("wheel: ({x}, {y}) [{unit:?}]");
|
||||
// let rem_x = (100. / x).abs() % 1.;
|
||||
// let rem_y = (100. / y).abs() % 1.;
|
||||
@@ -288,6 +288,6 @@ fn translate_fps_camera_events(
|
||||
#[inline]
|
||||
fn read_mouse_delta(mut mouse_motion: EventReader<MouseMotion>) -> Vec2 {
|
||||
mouse_motion
|
||||
.into_iter()
|
||||
.read()
|
||||
.fold(Vec2::ZERO, |accum, current| accum + current.delta)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ impl Plugin for SelectionPlugin {
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
wasm::notify_entity_selection_change
|
||||
.pipe(error)
|
||||
.map(bevy::utils::error)
|
||||
.run_if(resource_changed_or_removed::<Selection>()),
|
||||
);
|
||||
}
|
||||
@@ -47,7 +47,7 @@ fn update_selection(
|
||||
q_selectable: Query<&Selectable>,
|
||||
q_selected: Query<Entity, With<Selected>>,
|
||||
) {
|
||||
if let Some(event) = ev_select.iter().last() {
|
||||
if let Some(event) = ev_select.read().last() {
|
||||
// Clear any existing `Selected` components
|
||||
for ent in q_selected.iter() {
|
||||
cmd.entity(ent).remove::<Selected>();
|
||||
@@ -73,7 +73,7 @@ fn update_selection(
|
||||
} else {
|
||||
cmd.remove_resource::<Selection>();
|
||||
}
|
||||
} else if ev_input.iter().any(|action| {
|
||||
} else if ev_input.read().any(|action| {
|
||||
matches!(
|
||||
action,
|
||||
InputAction(Lifecycle::Stop, Action::Selection(input::Selection::Clear))
|
||||
|
||||
+16
-7
@@ -41,15 +41,24 @@ pub fn init(viewport_size: ViewportSize) {
|
||||
app.add_plugins(viewport::wasm::ViewportPlugin);
|
||||
|
||||
app.add_plugins((
|
||||
DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resolution: viewport_size.into(),
|
||||
title: "Storyteller Studio".into(),
|
||||
canvas: Some("#studio_canvas".into()),
|
||||
DefaultPlugins
|
||||
// TODO: To generate asset .meta files (to prevent 404 errors on the
|
||||
// web), it's currently necessary to uncomment the following
|
||||
// block and run the app with this command:
|
||||
// > cargo run -p studio --features bevy/asset_processor,bevy/tonemapping_luts
|
||||
// .set(AssetPlugin {
|
||||
// mode: AssetMode::Processed,
|
||||
// ..default()
|
||||
// })
|
||||
.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resolution: viewport_size.into(),
|
||||
title: "Storyteller Studio".into(),
|
||||
canvas: Some("#studio_canvas".into()),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}),
|
||||
DefaultPickingPlugins,
|
||||
DebugPlugin,
|
||||
InteractionPlugin,
|
||||
|
||||
+71
-30
@@ -1,5 +1,4 @@
|
||||
use bevy::{
|
||||
asset::LoadState,
|
||||
core_pipeline::{
|
||||
bloom::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings},
|
||||
fxaa::Fxaa,
|
||||
@@ -7,9 +6,9 @@ use bevy::{
|
||||
},
|
||||
gltf::{self, Gltf},
|
||||
math::vec3,
|
||||
pbr::NotShadowCaster,
|
||||
pbr::{NotShadowCaster, ShadowFilteringMethod},
|
||||
prelude::*,
|
||||
reflect::{TypePath, TypeUuid},
|
||||
reflect::TypePath,
|
||||
render::render_resource::{AsBindGroup, ShaderRef},
|
||||
utils::HashSet,
|
||||
};
|
||||
@@ -30,18 +29,29 @@ impl Plugin for ScenePlugin {
|
||||
.insert_resource(Msaa::Off)
|
||||
.add_plugins(MaterialPlugin::<ProceduralGridMaterial>::default())
|
||||
.add_systems(Startup, initialize)
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
spawn_new_gltf_scene.run_if(
|
||||
resource_exists::<NewGltf>()
|
||||
.and_then(new_gltf_loaded)
|
||||
.and_then(run_once()),
|
||||
),
|
||||
)
|
||||
.add_systems(
|
||||
Update,
|
||||
mark_scene_objects.run_if(
|
||||
resource_exists::<NewGltf>()
|
||||
.and_then(gltf_loaded)
|
||||
.and_then(new_gltf_loaded)
|
||||
.and_then(gltf_scene_spawned),
|
||||
),
|
||||
)
|
||||
.add_systems(PostUpdate, move_plane_with_camera.after(CameraMotionSystem));
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
app.add_systems(PostUpdate, wasm::notify_entity_spawn_changes.pipe(error));
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
wasm::notify_entity_spawn_changes.map(bevy::utils::error),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,14 +75,6 @@ fn initialize(
|
||||
|
||||
// glTF scene
|
||||
cmd.insert_resource(NewGltf(assets.load("gltf/sample-room.gltf")));
|
||||
cmd.spawn((
|
||||
Name::new("Scene"),
|
||||
Inspectable,
|
||||
SceneBundle {
|
||||
scene: assets.load("gltf/sample-room.gltf#Scene0"),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
|
||||
// Camera, graphics settings
|
||||
let focus = vec3(0.35011, 0.5, -0.99576);
|
||||
@@ -90,6 +92,7 @@ fn initialize(
|
||||
..default()
|
||||
},
|
||||
CameraControllerBundle::new(focus, camera_xform.translation),
|
||||
ShadowFilteringMethod::Hardware2x2,
|
||||
BloomSettings {
|
||||
composite_mode: BloomCompositeMode::EnergyConserving,
|
||||
intensity: 0.25,
|
||||
@@ -173,27 +176,66 @@ fn initialize(
|
||||
});
|
||||
}
|
||||
|
||||
fn gltf_loaded(assets: Res<AssetServer>, gltf: Res<NewGltf>) -> bool {
|
||||
assets.get_load_state(&**gltf) == LoadState::Loaded
|
||||
#[derive(Default)]
|
||||
struct LoadState(Handle<Gltf>, bool);
|
||||
|
||||
fn new_gltf_loaded(
|
||||
r_gltf: Res<NewGltf>,
|
||||
ra_gltfs: Res<Assets<Gltf>>,
|
||||
mut er_scene_events: EventReader<AssetEvent<Scene>>,
|
||||
mut l_loaded: Local<LoadState>,
|
||||
) -> bool {
|
||||
if l_loaded.0.path() != r_gltf.path() {
|
||||
*l_loaded = LoadState(r_gltf.clone(), false);
|
||||
} else if l_loaded.1 {
|
||||
return true;
|
||||
}
|
||||
|
||||
l_loaded.1 = er_scene_events.read().any(|event| match event {
|
||||
AssetEvent::LoadedWithDependencies { id } => {
|
||||
let gltf = ra_gltfs.get(&**r_gltf).unwrap();
|
||||
let Some(default_scene) = &gltf.default_scene else {
|
||||
return false;
|
||||
};
|
||||
|
||||
*id == default_scene.id()
|
||||
}
|
||||
_ => false,
|
||||
});
|
||||
|
||||
l_loaded.1
|
||||
}
|
||||
|
||||
fn spawn_new_gltf_scene(mut cmd: Commands, ra_gltfs: Res<Assets<Gltf>>, r_gltf: Res<NewGltf>) {
|
||||
let gltf = ra_gltfs.get(&**r_gltf).unwrap();
|
||||
let Some(scene) = &gltf.default_scene else {
|
||||
return;
|
||||
};
|
||||
|
||||
cmd.spawn((
|
||||
Name::new("Scene"),
|
||||
Inspectable,
|
||||
SceneBundle {
|
||||
scene: scene.clone(),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
fn gltf_scene_spawned(
|
||||
r_assets: Res<AssetServer>,
|
||||
r_gltf: Res<NewGltf>,
|
||||
ra_gltfs: Res<Assets<Gltf>>,
|
||||
q_scenes: Query<&Handle<Scene>, (With<Name>, With<Children>)>,
|
||||
) -> bool {
|
||||
let gltf = ra_gltfs.get(&r_gltf).unwrap();
|
||||
let Some(gltf_scene_path) = gltf
|
||||
.default_scene
|
||||
.as_ref()
|
||||
.and_then(|handle| r_assets.get_handle_path(handle))
|
||||
else {
|
||||
let gltf = ra_gltfs.get(&**r_gltf).unwrap();
|
||||
|
||||
let Some(gltf_scene_path) = gltf.default_scene.as_ref().and_then(|handle| handle.path()) else {
|
||||
warn!("No default scene found for glTF: {:#?}", gltf);
|
||||
return false;
|
||||
};
|
||||
|
||||
q_scenes.iter().any(|handle| {
|
||||
let Some(path) = r_assets.get_handle_path(handle) else {
|
||||
let Some(path) = handle.path() else {
|
||||
return false;
|
||||
};
|
||||
path == gltf_scene_path
|
||||
@@ -203,14 +245,15 @@ fn gltf_scene_spawned(
|
||||
fn mark_scene_objects(
|
||||
mut cmd: Commands,
|
||||
r_gltf: Res<NewGltf>,
|
||||
r_assets: Res<AssetServer>,
|
||||
ra_gltfs: Res<Assets<Gltf>>,
|
||||
ra_gltf_nodes: Res<Assets<gltf::GltfNode>>,
|
||||
ra_gltf_meshes: Res<Assets<gltf::GltfMesh>>,
|
||||
q_parents: Query<(Entity, &Name, &Children), Without<Selectable>>,
|
||||
q_primitives: Query<&Handle<Mesh>>,
|
||||
) {
|
||||
let gltf = ra_gltfs.get(&r_gltf).unwrap();
|
||||
info!("mark_scene_objects");
|
||||
|
||||
let gltf = ra_gltfs.get(&**r_gltf).unwrap();
|
||||
|
||||
for (ent_parent, name, children) in q_parents.iter() {
|
||||
if gltf.named_nodes.contains_key(&**name) {
|
||||
@@ -241,7 +284,7 @@ fn mark_scene_objects(
|
||||
let prims_from_gltf = gltf_mesh
|
||||
.primitives
|
||||
.iter()
|
||||
.filter_map(|prim| r_assets.get_handle_path(&prim.mesh))
|
||||
.filter_map(|prim| prim.mesh.path())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
// Collect all of the mesh handles in this entity's children
|
||||
@@ -251,11 +294,10 @@ fn mark_scene_objects(
|
||||
q_primitives
|
||||
.get(*ent_child)
|
||||
.ok()
|
||||
.and_then(|handle| r_assets.get_handle_path(handle))
|
||||
.and_then(|handle| handle.path())
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
|
||||
// If the sets match, this is the entity that represents the glTF mesh
|
||||
if prims_from_gltf == prims_from_ecs {
|
||||
cmd.entity(ent_parent).insert(Selectable);
|
||||
@@ -283,8 +325,7 @@ fn move_plane_with_camera(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AsBindGroup, Clone, TypePath, TypeUuid)]
|
||||
#[uuid = "CE331A13-F247-4F5B-A75E-670B2BD5776A"]
|
||||
#[derive(Asset, AsBindGroup, TypePath, Clone)]
|
||||
struct ProceduralGridMaterial {}
|
||||
|
||||
impl Material for ProceduralGridMaterial {
|
||||
|
||||
+14
-3
@@ -52,9 +52,20 @@ fn skybox_assets_loaded(
|
||||
return false;
|
||||
};
|
||||
|
||||
assets.get_load_state(skybox_assets.cubemap.clone_weak()) == LoadState::Loaded
|
||||
&& assets.get_load_state(skybox_assets.env_diffuse.clone_weak()) == LoadState::Loaded
|
||||
&& assets.get_load_state(skybox_assets.env_specular.clone_weak()) == LoadState::Loaded
|
||||
let load_states = (
|
||||
assets.get_load_state(skybox_assets.cubemap.clone_weak()),
|
||||
assets.get_load_state(skybox_assets.env_diffuse.clone_weak()),
|
||||
assets.get_load_state(skybox_assets.env_specular.clone_weak()),
|
||||
);
|
||||
|
||||
matches!(
|
||||
load_states,
|
||||
(
|
||||
Some(LoadState::Loaded),
|
||||
Some(LoadState::Loaded),
|
||||
Some(LoadState::Loaded),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn spawn_skybox(
|
||||
|
||||
@@ -78,7 +78,7 @@ pub mod wasm {
|
||||
mut events: EventReader<ViewportResizeEvent>,
|
||||
mut window: Query<&mut Window>,
|
||||
) {
|
||||
if let Some(event) = events.into_iter().last() {
|
||||
if let Some(event) = events.read().last() {
|
||||
let ViewportSize { width, height } = event.0;
|
||||
window.single_mut().resolution.set(width, height);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user