diff --git a/Cargo.toml b/Cargo.toml index af06c011..a3e50907 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,11 +29,11 @@ rand_pcg = "0.3" serde = { version = "1.0", features = ["derive"] } anyhow = "1.0" ron = "0.8" -bitflags = "1.3" +bitflags = "2.3" typetag = "0.2" [dependencies.bevy] -version = "0.10" +git = "https://github.com/bevyengine/bevy" default-features = false features = [ "bevy_core_pipeline", "bevy_render", "bevy_asset", "x11" ] @@ -41,10 +41,10 @@ features = [ "bevy_core_pipeline", "bevy_render", "bevy_asset", "x11" ] all-features = true [dev-dependencies] -# Same version as Bevy 0.10 (bevy_render) -wgpu = "0.15" +# Same version as Bevy 0.11 (bevy_render) +wgpu = "0.16" # For shader snippet validation -naga = "0.11" +naga = "0.12" futures = "0.3" bevy-inspector-egui = "0.18" diff --git a/README.md b/README.md index 40fc9d2b..481a6645 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ use bevy_hanabi::prelude::*; App::default() .add_plugins(DefaultPlugins) - .add_plugin(HanabiPlugin) + .add_plugins(HanabiPlugin) .run(); ``` diff --git a/examples/2d.rs b/examples/2d.rs index f29790ec..26ffe5d6 100644 --- a/examples/2d.rs +++ b/examples/2d.rs @@ -12,7 +12,7 @@ use bevy::{ }, sprite::{MaterialMesh2dBundle, Mesh2dHandle}, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -32,11 +32,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update_plane) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update_plane)) .run(); Ok(()) diff --git a/examples/activate.rs b/examples/activate.rs index c7b9e2ba..aec9d855 100644 --- a/examples/activate.rs +++ b/examples/activate.rs @@ -1,6 +1,7 @@ //! A circle bobs up and down in the water, //! spawning square bubbles when in the water. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ @@ -10,7 +11,7 @@ use bevy::{ RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -30,11 +31,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update)) .run(); Ok(()) @@ -51,7 +52,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; let mut projection = OrthographicProjection::default(); projection.scaling_mode = ScalingMode::FixedVertical(2.); projection.scale = 1.0; diff --git a/examples/billboard.rs b/examples/billboard.rs index 8bbd7456..bdf7df3b 100644 --- a/examples/billboard.rs +++ b/examples/billboard.rs @@ -2,13 +2,14 @@ //! particles to always render facing the camera. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ camera::Projection, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -28,11 +29,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(rotate_camera) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, rotate_camera)) .run(); Ok(()) @@ -51,6 +52,7 @@ fn setup( fov: 120.0, ..Default::default() }), + tonemapping: Tonemapping::None, ..Default::default() }; diff --git a/examples/circle.rs b/examples/circle.rs index da03585a..da34d22e 100644 --- a/examples/circle.rs +++ b/examples/circle.rs @@ -3,11 +3,12 @@ //! A sphere spawns dust in a circle. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin}, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -27,10 +28,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -43,7 +45,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform = Transform::from_xyz(3.0, 3.0, 5.0).looking_at(Vec3::new(0.0, 1.0, 0.0), Vec3::Y); commands.spawn(camera); diff --git a/examples/expr.rs b/examples/expr.rs index edd4c439..38d13cda 100644 --- a/examples/expr.rs +++ b/examples/expr.rs @@ -8,11 +8,13 @@ //! based on [`ExprWriter::time()`] then assigned to the [`AccelModifier`]. use bevy::{ - core_pipeline::{bloom::BloomSettings, clear_color::ClearColorConfig}, + core_pipeline::{ + bloom::BloomSettings, clear_color::ClearColorConfig, tonemapping::Tonemapping, + }, log::LogPlugin, prelude::*, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -22,10 +24,10 @@ fn main() -> Result<(), Box> { level: bevy::log::Level::WARN, filter: "bevy_hanabi=warn,expr=trace".to_string(), })) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + //.add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -44,6 +46,7 @@ fn setup(mut commands: Commands, mut effects: ResMut>) { clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }, + tonemapping: Tonemapping::None, ..default() }, BloomSettings::default(), diff --git a/examples/firework.rs b/examples/firework.rs index 0a71dd44..8c7a4d23 100644 --- a/examples/firework.rs +++ b/examples/firework.rs @@ -15,11 +15,13 @@ //! increased realism. This is a subtle effect, but of importance. use bevy::{ - core_pipeline::{bloom::BloomSettings, clear_color::ClearColorConfig}, + core_pipeline::{ + bloom::BloomSettings, clear_color::ClearColorConfig, tonemapping::Tonemapping, + }, log::LogPlugin, prelude::*, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -29,10 +31,11 @@ fn main() -> Result<(), Box> { level: bevy::log::Level::WARN, filter: "bevy_hanabi=warn,firework=trace".to_string(), })) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -50,6 +53,7 @@ fn setup(mut commands: Commands, mut effects: ResMut>) { clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }, + tonemapping: Tonemapping::None, ..default() }, BloomSettings::default(), diff --git a/examples/force_field.rs b/examples/force_field.rs index 575aa5c8..25eec434 100644 --- a/examples/force_field.rs +++ b/examples/force_field.rs @@ -11,13 +11,14 @@ //! killing all particles entering it. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ camera::Projection, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -42,13 +43,13 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - //.add_plugin(LookTransformPlugin) - //.add_plugin(OrbitCameraPlugin::default()) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update) + //.add_plugins(LookTransformPlugin) + //.add_plugins(OrbitCameraPlugin::default()) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update)) .run(); Ok(()) @@ -62,7 +63,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; let mut projection = OrthographicProjection::default(); projection.scaling_mode = bevy::render::camera::ScalingMode::FixedVertical(5.); camera.transform.translation.z = projection.far / 2.0; diff --git a/examples/gradient.rs b/examples/gradient.rs index f4c973b5..3abf1f60 100644 --- a/examples/gradient.rs +++ b/examples/gradient.rs @@ -1,4 +1,5 @@ use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ @@ -6,7 +7,7 @@ use bevy::{ view::RenderLayers, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use std::f32::consts::PI; use bevy_hanabi::prelude::*; @@ -27,11 +28,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update)) .run(); Ok(()) @@ -51,6 +52,7 @@ fn setup( hdr: true, ..default() }, + tonemapping: Tonemapping::None, ..default() }; camera.transform.translation = Vec3::new(0.0, 0.0, 100.0); diff --git a/examples/init.rs b/examples/init.rs index ea03b9a1..f5a1ed1c 100644 --- a/examples/init.rs +++ b/examples/init.rs @@ -8,13 +8,14 @@ use std::f32::consts::PI; use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ mesh::shape::Cube, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -34,11 +35,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(rotate_camera) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, rotate_camera)) .run(); Ok(()) @@ -101,7 +102,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 50.0); commands.spawn(camera); diff --git a/examples/instancing.rs b/examples/instancing.rs index e3615076..35a48dd6 100644 --- a/examples/instancing.rs +++ b/examples/instancing.rs @@ -9,8 +9,10 @@ #![allow(dead_code)] -use bevy::{log::LogPlugin, prelude::*, render::mesh::shape::Cube}; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::mesh::shape::Cube, +}; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use rand::Rng; use bevy_hanabi::prelude::*; @@ -173,12 +175,12 @@ fn main() { level: bevy::log::Level::WARN, filter: "bevy_hanabi=warn,instancing=trace".to_string(), })) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) .insert_resource(InstanceManager::new(5, 4)) - .add_startup_system(setup) - .add_system(keyboard_input_system) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, keyboard_input_system)) //.add_system(stress_test.after(keyboard_input_system)) .run(); } @@ -192,7 +194,10 @@ fn setup( ) { info!("Usage: Press the SPACE key to spawn more instances, and the DELETE key to remove an existing instance."); - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 180.0); commands.spawn(camera); diff --git a/examples/lifetime.rs b/examples/lifetime.rs index a60d6a97..6018acdd 100644 --- a/examples/lifetime.rs +++ b/examples/lifetime.rs @@ -12,13 +12,14 @@ //! spawns some more. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ mesh::shape::Cube, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -38,10 +39,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -53,7 +55,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 180.0); commands.spawn(camera); diff --git a/examples/multicam.rs b/examples/multicam.rs index a4aeca72..c4efebce 100644 --- a/examples/multicam.rs +++ b/examples/multicam.rs @@ -1,5 +1,5 @@ use bevy::{ - core_pipeline::clear_color::ClearColorConfig, + core_pipeline::{clear_color::ClearColorConfig, tonemapping::Tonemapping}, log::LogPlugin, math::EulerRot, prelude::*, @@ -10,7 +10,7 @@ use bevy::{ }, window::WindowResized, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -20,11 +20,14 @@ fn main() { level: bevy::log::Level::WARN, filter: "bevy_hanabi=warn,multicam=trace".to_string(), })) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update_camera_viewports) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems( + Update, + (bevy::window::close_on_esc, update_camera_viewports), + ) .run(); } @@ -114,6 +117,7 @@ fn setup( }, transform: Transform::from_translation(Vec3::new(x, 100.0, z)) .looking_at(Vec3::ZERO, Vec3::Y), + tonemapping: Tonemapping::None, ..default() }, SplitCamera { diff --git a/examples/portal.rs b/examples/portal.rs index eed59310..cf659160 100644 --- a/examples/portal.rs +++ b/examples/portal.rs @@ -10,11 +10,13 @@ //! before they disappear, like sparkles fading away. use bevy::{ - core_pipeline::{bloom::BloomSettings, clear_color::ClearColorConfig}, + core_pipeline::{ + bloom::BloomSettings, clear_color::ClearColorConfig, tonemapping::Tonemapping, + }, log::LogPlugin, prelude::*, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -22,12 +24,13 @@ fn main() -> Result<(), Box> { App::default() .add_plugins(DefaultPlugins.set(LogPlugin { level: bevy::log::Level::WARN, - filter: "bevy_hanabi=warn,portal=trace".to_string(), + filter: "bevy_hanabi=trace,portal=trace".to_string(), })) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -45,6 +48,7 @@ fn setup(mut commands: Commands, mut effects: ResMut>) { clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }, + tonemapping: Tonemapping::None, ..default() }, BloomSettings::default(), diff --git a/examples/random.rs b/examples/random.rs index 7d2b3ef3..1bfa1c01 100644 --- a/examples/random.rs +++ b/examples/random.rs @@ -2,13 +2,14 @@ //! Spawns a random number of particles at random times. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ mesh::shape::Cube, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -28,10 +29,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) + .add_systems(Update, bevy::window::close_on_esc) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) .run(); Ok(()) @@ -43,7 +45,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 100.0); commands.spawn(camera); diff --git a/examples/spawn.rs b/examples/spawn.rs index 89e8ed48..4d84d81d 100644 --- a/examples/spawn.rs +++ b/examples/spawn.rs @@ -1,4 +1,5 @@ use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ @@ -7,7 +8,7 @@ use bevy::{ RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -39,11 +40,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update_accel) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update_accel)) .run(); Ok(()) @@ -61,7 +62,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 100.0); commands.spawn(camera); diff --git a/examples/spawn_on_command.rs b/examples/spawn_on_command.rs index 1d7f7da5..59c8f64c 100644 --- a/examples/spawn_on_command.rs +++ b/examples/spawn_on_command.rs @@ -1,6 +1,7 @@ //! A circle bounces around in a box and spawns particles //! when it hits the wall. use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, math::Vec3Swizzles, prelude::*, @@ -11,7 +12,7 @@ use bevy::{ RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -31,11 +32,11 @@ fn main() -> Result<(), Box> { }) .set(RenderPlugin { wgpu_settings }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update)) .run(); Ok(()) @@ -55,7 +56,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; let mut projection = OrthographicProjection::default(); projection.scaling_mode = ScalingMode::FixedVertical(2.); projection.scale = 1.2; @@ -97,14 +101,27 @@ fn setup( }) .insert(Name::new("ball")); - let spawner = Spawner::once(30.0.into(), false); + // Set `spawn_immediately` to false to spawn on command with Spawner::reset() + let spawner = Spawner::once(100.0.into(), false); let writer = ExprWriter::new(); - let lifetime = writer.lit(5.).expr(); + // Init the age of particles to 0, and their lifetime to 1.5 second. + let age = writer.lit(0.).expr(); + let init_age = InitAttributeModifier::new(Attribute::AGE, age); + let lifetime = writer.lit(1.5).expr(); let init_lifetime = InitAttributeModifier::new(Attribute::LIFETIME, lifetime); - // Bind the initial particle color to the value of the 'my_color' property. + // Add a bit of linear drag to slow down particles after the inital spawning. + // This keeps the particle around the spawn point, making it easier to visualize + // the different groups of particles. + let drag = writer.lit(2.).expr(); + let update_drag = LinearDragModifier::new(drag); + + // Bind the initial particle color to the value of the 'my_color' property when + // the particle spawns. The particle will keep that color afterward, even if the + // property changes, because the color will be saved per-particle (due to the + // Attribute::COLOR). let color = writer.prop("my_color").expr(); let init_color = InitAttributeModifier::new(Attribute::COLOR, color); @@ -121,12 +138,13 @@ fn setup( center: Vec3::ZERO, speed: 0.2.into(), }) + .init(init_age) .init(init_lifetime) .init(init_color) - // Set a size of 3->10 (logical) pixels, constant in screen space, independent of - // projection, but varying over the lifetime of the particle. - .render(SizeOverLifetimeModifier { - gradient: Gradient::linear(Vec2::splat(3.), Vec2::splat(10.)), + .update(update_drag) + // Set a size of 3 (logical) pixels, constant in screen space, independent of projection + .render(SetSizeModifier { + size: Vec2::splat(3.).into(), screen_space_size: true, }), ); diff --git a/examples/visibility.rs b/examples/visibility.rs index 0cf9afae..498e1676 100644 --- a/examples/visibility.rs +++ b/examples/visibility.rs @@ -13,13 +13,14 @@ use std::time::Duration; use bevy::{ + core_pipeline::tonemapping::Tonemapping, log::LogPlugin, prelude::*, render::{ mesh::shape::Cube, render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin, }, }; -use bevy_inspector_egui::quick::WorldInspectorPlugin; +// use bevy_inspector_egui::quick::WorldInspectorPlugin; use bevy_hanabi::prelude::*; @@ -46,11 +47,11 @@ fn main() -> Result<(), Box> { ..default() }), ) - .add_system(bevy::window::close_on_esc) - .add_plugin(HanabiPlugin) - .add_plugin(WorldInspectorPlugin::default()) - .add_startup_system(setup) - .add_system(update) + .add_plugins(HanabiPlugin) + // Have to wait for update. + // .add_plugins(WorldInspectorPlugin::default()) + .add_systems(Startup, setup) + .add_systems(Update, (bevy::window::close_on_esc, update)) .run(); Ok(()) @@ -62,7 +63,10 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut camera = Camera3dBundle::default(); + let mut camera = Camera3dBundle { + tonemapping: Tonemapping::None, + ..default() + }; camera.transform.translation = Vec3::new(0.0, 0.0, 100.0); commands.spawn(camera); diff --git a/src/asset.rs b/src/asset.rs index de3158ea..24d859f8 100644 --- a/src/asset.rs +++ b/src/asset.rs @@ -1,6 +1,6 @@ use bevy::{ asset::{AssetLoader, LoadContext, LoadedAsset}, - reflect::{FromReflect, Reflect, TypeUuid}, + reflect::{Reflect, TypeUuid}, utils::{BoxedFuture, HashSet}, }; use serde::{Deserialize, Serialize}; @@ -12,9 +12,7 @@ use crate::{ }; /// Type of motion integration applied to the particles of a system. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum MotionIntegration { /// No motion integration. The [`Attribute::POSITION`] of the particles /// needs to be explicitly assigned by a modifier for the particles to move. @@ -39,9 +37,7 @@ pub enum MotionIntegration { } /// Simulation condition for an effect. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum SimulationCondition { /// Simulate the effect only when visible. /// @@ -87,7 +83,8 @@ pub enum SimulationCondition { /// /// [`ParticleEffect`]: crate::ParticleEffect /// [`ParticleEffectBundle`]: crate::ParticleEffectBundle -#[derive(Default, Clone, TypeUuid, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Default, Clone, TypeUuid, Reflect, Serialize, Deserialize)] +#[reflect(from_reflect = false)] #[uuid = "249aefa4-9b8e-48d3-b167-3adf6c081c34"] pub struct EffectAsset { /// Display name of the effect. diff --git a/src/attributes.rs b/src/attributes.rs index e9825ee0..81bfa767 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -3,8 +3,9 @@ use std::{any::Any, borrow::Cow, num::NonZeroU64}; use bevy::{ math::{Vec2, Vec3, Vec4}, reflect::{ - utility::NonGenericTypeInfoCell, DynamicStruct, FieldIter, FromReflect, NamedField, - Reflect, ReflectMut, ReflectOwned, ReflectRef, Struct, StructInfo, TypeInfo, Typed, + utility::{GenericTypePathCell, NonGenericTypeInfoCell}, + DynamicStruct, FieldIter, FromReflect, NamedField, Reflect, ReflectMut, ReflectOwned, + ReflectRef, Struct, StructInfo, TypeInfo, TypePath, Typed, }, }; use serde::{Deserialize, Serialize}; @@ -15,7 +16,7 @@ use crate::{ }; /// Scalar types. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] #[non_exhaustive] pub enum ScalarType { /// Boolean value (`bool`). @@ -71,7 +72,7 @@ impl ToWgslString for ScalarType { } /// Vector type (`vecN`). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub struct VectorType { /// Type of all elements (components) of the vector. elem_type: ScalarType, @@ -162,7 +163,7 @@ impl ToWgslString for VectorType { } /// Floating-point matrix type (`matCxR`). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub struct MatrixType { rows: u8, cols: u8, @@ -312,7 +313,7 @@ impl ToWgslString for ValueType { } } -#[derive(Debug, Clone, Reflect, FromReflect)] +#[derive(Debug, Clone, Reflect)] pub(crate) struct AttributeInner { name: Cow<'static, str>, default_value: Value, @@ -425,6 +426,30 @@ impl From for &'static str { } } +impl TypePath for Attribute { + fn type_path() -> &'static str { + static CELL: GenericTypePathCell = GenericTypePathCell::new(); + CELL.get_or_insert::(|| "bevy_hanabi::attribute::Attribute".to_owned()) + } + + fn short_type_path() -> &'static str { + static CELL: GenericTypePathCell = GenericTypePathCell::new(); + CELL.get_or_insert::(|| "Attribute".to_owned()) + } + + fn type_ident() -> Option<&'static str> { + Some("Attribute") + } + + fn crate_name() -> Option<&'static str> { + Some("bevy_hanabi") + } + + fn module_path() -> Option<&'static str> { + Some("bevy_hanabi::attribute") + } +} + impl Typed for Attribute { fn type_info() -> &'static TypeInfo { static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); @@ -484,7 +509,7 @@ impl Struct for Attribute { fn clone_dynamic(&self) -> DynamicStruct { let mut dynamic = DynamicStruct::default(); - dynamic.set_name(::std::string::ToString::to_string(Reflect::type_name(self))); + dynamic.set_represented_type(self.get_represented_type_info()); dynamic.insert_boxed("name", Reflect::clone_value(&self.0.name)); dynamic.insert_boxed("default_value", Reflect::clone_value(&self.0.default_value)); dynamic @@ -497,9 +522,8 @@ impl Reflect for Attribute { ::core::any::type_name::() } - #[inline] - fn get_type_info(&self) -> &'static TypeInfo { - ::type_info() + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) } #[inline] @@ -1150,13 +1174,13 @@ mod tests { math::{Vec2, Vec3, Vec4}, reflect::TypeRegistration, }; - use naga::{front::wgsl::Parser, proc::Layouter}; + use naga::{front::wgsl::Frontend, proc::Layouter}; // Ensure the size and alignment of all types conforms to the WGSL spec by // querying naga as a reference. #[test] fn value_type_align() { - let mut parser = Parser::new(); + let mut frontend = Frontend::new(); for (value_type, value) in &[ ( ValueType::Scalar(ScalarType::Float), @@ -1203,7 +1227,7 @@ mod tests { // Create a tiny WGSL snippet with the Value(Type) and parse it let src = format!("const x = {};", value.to_wgsl_string()); - let res = parser.parse(&src); + let res = frontend.parse(&src); if let Err(err) = &res { println!("Error: {:?}", err); } @@ -1311,7 +1335,10 @@ mod tests { } let d = s.clone_dynamic(); - assert_eq!(TypeRegistration::of::().type_name(), d.name()); + assert_eq!( + TypeRegistration::of::().type_name(), + d.get_represented_type_info().unwrap().type_name() + ); assert_eq!(Some(0), d.index_of("name")); assert_eq!(Some(1), d.index_of("default_value")); } diff --git a/src/gradient.rs b/src/gradient.rs index 6e77d552..91595e6f 100644 --- a/src/gradient.rs +++ b/src/gradient.rs @@ -59,7 +59,7 @@ impl Lerp for Quat { } /// A single key point for a [`Gradient`]. -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct GradientKey { /// Ratio in \[0:1\] where the key is located. ratio: f32, @@ -117,7 +117,7 @@ impl Hash for GradientKey { /// The gradient can be sampled anywhere, and will return a linear interpolation /// of the values of its closest keys. Sampling before 0 or after 1 returns a /// constant value equal to the one of the closest bound. -#[derive(Debug, Default, Clone, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Reflect, Serialize, Deserialize)] pub struct Gradient { keys: Vec>, } diff --git a/src/graph/expr.rs b/src/graph/expr.rs index 2e263b70..5344313b 100644 --- a/src/graph/expr.rs +++ b/src/graph/expr.rs @@ -101,12 +101,9 @@ //! [`Modifier`]: crate::Modifier //! [`EffectAsset`]: crate::EffectAsset -use std::{cell::RefCell, cmp::Ordering, fmt, marker::PhantomData, num::NonZeroU32, rc::Rc}; +use std::{cell::RefCell, num::NonZeroU32, rc::Rc}; -use bevy::{ - reflect::{FromReflect, Reflect}, - utils::thiserror::Error, -}; +use bevy::{reflect::Reflect, utils::thiserror::Error}; use serde::{Deserialize, Serialize}; use crate::{Attribute, PropertyLayout, ScalarType, ToWgslString, ValueType}; @@ -115,89 +112,32 @@ use super::Value; type Index = NonZeroU32; -/// Typed handle uniquely identifying an element into an implicitly-referenced -/// storage. +/// Handle of an expression inside a given [`Module`]. /// -/// The handle is a convenience wrapper around an index into an internal storage -/// implicitly associated with it. The handle itself is very lightweight, and -/// doesn't keep a reference to the storage; it's the user responsibility to -/// ensure the lifetime of the handle is longer than those of the handle itself. -#[derive(Reflect, FromReflect, Serialize, Deserialize)] -pub struct Handle { +/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a +/// lightweight representation, similar to a simple array index. For this +/// reason, it's easily copyable. However it's also lacking any kind of error +/// checking, and mixing handles to different modules produces undefined +/// behaviors (like an index does when indexing the wrong array). +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize, +)] +pub struct ExprHandle { index: Index, - #[serde(skip)] - #[reflect(ignore)] - marker: PhantomData, -} - -impl Clone for Handle { - fn clone(&self) -> Self { - Handle { - index: self.index, - marker: self.marker, - } - } } -impl Copy for Handle {} - -impl PartialEq for Handle { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } -} - -impl Eq for Handle {} - -impl PartialOrd for Handle { - fn partial_cmp(&self, other: &Self) -> Option { - self.index.partial_cmp(&other.index) - } -} - -impl Ord for Handle { - fn cmp(&self, other: &Self) -> Ordering { - self.index.cmp(&other.index) - } -} - -impl fmt::Debug for Handle { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "[{}]", self.index) - } -} - -impl std::hash::Hash for Handle { - fn hash(&self, hasher: &mut H) { - self.index.hash(hasher) - } -} - -impl Handle { - fn new(index: Index) -> Handle { - Handle { - index, - marker: PhantomData, - } +impl ExprHandle { + /// Create a new handle from a 1-based [`Index`]. + fn new(index: Index) -> Self { + Self { index } } + /// Get the zero-based index into the array of the module. fn index(&self) -> usize { (self.index.get() - 1) as usize } } -/// Handle of an expression inside a given [`Module`]. -/// -/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a -/// lightweight representation, similar to a simple array index. For this -/// reason, it's easily copyable. However it's also lacking any kind of error -/// checking, and mixing handles to different modules produces undefined -/// behaviors (like an index does when indexing the wrong array). -/// -/// The `ExprHandle` alias should always be preferred over its underlying -/// `Handle` type, to avoid confusion with Bevy's own `Handle` type. -pub type ExprHandle = Handle; - /// Container for expressions. /// /// A module represents a storage for a set of expressions used in a single @@ -217,7 +157,7 @@ pub type ExprHandle = Handle; /// [`EffectAsset`]: crate::EffectAsset /// [`lit()`]: Module::lit /// [`attr()`]: Module::attr -#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct Module { expressions: Vec, } @@ -233,7 +173,7 @@ impl Module { #[allow(unsafe_code)] let index: Index = unsafe { NonZeroU32::new_unchecked(self.expressions.len() as u32 + 1) }; self.expressions.push(expr.into()); - Handle::new(index) + ExprHandle::new(index) } /// Build a literal expression and append it to the module. @@ -500,14 +440,14 @@ pub trait EvalContext { fn property_layout(&self) -> &PropertyLayout; /// Resolve an expression handle its the underlying expression. - fn expr(&self, handle: Handle) -> Result<&Expr, ExprError>; + fn expr(&self, handle: ExprHandle) -> Result<&Expr, ExprError>; /// Evaluate an expression. - fn eval(&self, handle: Handle) -> Result; + fn eval(&self, handle: ExprHandle) -> Result; } /// Language expression producing a value. -#[derive(Debug, Clone, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub enum Expr { /// Built-in expression ([`BuiltInExpr`]) providing access to some internal /// quantities like the simulation time. @@ -528,16 +468,16 @@ pub enum Expr { /// Unary operator. op: UnaryOperator, /// Operand the unary operation applies to. - expr: Handle, + expr: ExprHandle, }, /// Binary operation expression, composing two expressions into a third one. Binary { /// Binary operator. op: BinaryOperator, /// Left-hand side operand the binary operation applies to. - left: Handle, + left: ExprHandle, /// Right-hand side operand the binary operation applies to. - right: Handle, + right: ExprHandle, }, } @@ -670,7 +610,7 @@ impl Expr { /// constant itself. /// /// [`is_const()`]: LiteralExpr::is_const -#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct LiteralExpr { value: Value, } @@ -724,7 +664,7 @@ impl> From for LiteralExpr { } /// Expression representing the value of an attribute of a particle. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub struct AttributeExpr { attr: Attribute, } @@ -766,7 +706,7 @@ impl From for AttributeExpr { } /// Expression representing the value of a property of an effect. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub struct PropertyExpr { property_name: String, } @@ -812,7 +752,7 @@ impl From for PropertyExpr { } /// Built-in operators. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum BuiltInOperator { /// Current effect system simulation time since startup, in seconds. Time, @@ -855,7 +795,7 @@ impl ToWgslString for BuiltInOperator { } /// Expression for getting built-in quantities related to the effect system. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub struct BuiltInExpr { operator: BuiltInOperator, } @@ -895,7 +835,7 @@ impl ToWgslString for BuiltInExpr { /// Operator applied to a single operand to produce another value. The type of /// the operand and the result are not necessarily the same. Valid operand types /// depend on the operator itself. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum UnaryOperator { /// Absolute value operator. /// @@ -946,7 +886,7 @@ impl ToWgslString for UnaryOperator { /// Operator applied between two operands, generally denoted "left" and "right". /// The type of the operands and the result are not necessarily the same. Valid /// operand types depend on the operator itself. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum BinaryOperator { /// Addition operator. /// @@ -1281,7 +1221,7 @@ impl ExprWriter { /// ``` #[derive(Debug)] pub struct WriterExpr { - expr: Handle, + expr: ExprHandle, module: Rc>, } @@ -1752,7 +1692,7 @@ impl WriterExpr { /// // Retrieve the ExprHandle for that expression. /// let handle = x.expr(); /// ``` - pub fn expr(self) -> Handle { + pub fn expr(self) -> ExprHandle { self.expr } } @@ -1962,10 +1902,10 @@ mod tests { // let l_serde: LiteralExpr = ron::from_str(&s).unwrap(); // assert_eq!(l_serde, l); - // let b: Handle = Box::new(l); + // let b: ExprHandle = Box::new(l); // let s = ron::to_string(&b).unwrap(); // println!("boxed literal: {:?}", s); - // let b_serde: Handle = ron::from_str(&s).unwrap(); + // let b_serde: ExprHandle = ron::from_str(&s).unwrap(); // assert!(b_serde.is_const()); // assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string()); diff --git a/src/graph/mod.rs b/src/graph/mod.rs index a0f63aa1..4d49ba0f 100644 --- a/src/graph/mod.rs +++ b/src/graph/mod.rs @@ -43,7 +43,7 @@ use std::fmt::Debug; use bevy::{ math::{BVec2, BVec3, BVec4, IVec2, IVec3, IVec4, Vec2, Vec3, Vec3A, Vec4}, - reflect::{FromReflect, Reflect}, + reflect::Reflect, utils::FloatOrd, }; use serde::{Deserialize, Serialize}; @@ -62,58 +62,6 @@ pub use node::{ SubNode, TimeNode, }; -// /// Binary arithmetic operator. -// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, FromReflect, -// Serialize, Deserialize)] #[non_exhaustive] -// pub enum BinaryOperator { -// /// Add operator `+`. -// Add, -// /// Subtract operator `-`. -// Sub, -// /// Multiply operator `*`. -// Mul, -// /// Divide operator `/`. -// Div, -// } - -// impl BinaryOperator { -// /// Apply the operator to a pair of `f32` values. -// pub fn apply_f32(&self, a: f32, b: f32) -> f32 { -// match *self { -// BinaryOperator::Add => a + b, -// BinaryOperator::Sub => a - b, -// BinaryOperator::Mul => a * b, -// BinaryOperator::Div => a / b, -// } -// } - -// /// Apply the operator to a pair of `i32` values. -// pub fn apply_i32(&self, a: i32, b: i32) -> i32 { -// match *self { -// BinaryOperator::Add => a + b, -// BinaryOperator::Sub => a - b, -// BinaryOperator::Mul => a * b, -// BinaryOperator::Div => a / b, -// } -// } - -// /// Apply the operator to a pair of `u32` values. -// pub fn apply_u32(&self, a: u32, b: u32) -> u32 { -// match *self { -// BinaryOperator::Add => a + b, -// BinaryOperator::Sub => a - b, -// BinaryOperator::Mul => a * b, -// BinaryOperator::Div => a / b, -// } -// } -// } - -// /// Binary arithmetic operation over self. -// pub trait BinaryOperation { -// /// Apply a binary arithmetic operator between self and another value. -// fn apply(&self, other: &Self, op: BinaryOperator) -> Self; -// } - /// Variant storage for a scalar value. #[derive(Debug)] #[non_exhaustive] @@ -128,22 +76,8 @@ pub enum ScalarValueMut<'a> { Uint(&'a mut u32), } -// impl<'a> ScalarValueMut<'a> { -// /// Apply a binary arithmetic operator between self and another operand. -// fn binary_op(&mut self, other: &ScalarValue, op: BinaryOperator) { -// match self { -// ScalarValueMut::Bool(_) => { -// panic!("Cannot apply binary arithmetic operator to boolean -// value.") } -// ScalarValueMut::Float(f) => **f = op.apply_f32(**f, -// other.as_f32()), ScalarValueMut::Int(i) => **i = -// op.apply_i32(**i, other.as_i32()), ScalarValueMut::Uint(u) => **u -// = op.apply_u32(**u, other.as_u32()), } -// } -// } - /// Variant storage for a scalar value. -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] #[non_exhaustive] pub enum ScalarValue { /// Single `bool` value. @@ -450,7 +384,7 @@ impl ElemType for u32 { } /// Variant storage for a vector value. -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct VectorValue { vector_type: VectorType, storage: [u32; 4], @@ -1073,7 +1007,7 @@ impl From for VectorValue { } /// Floating-point matrix value. -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct MatrixValue { /// Matrix type. matrix_type: MatrixType, @@ -1199,7 +1133,7 @@ impl ToWgslString for MatrixValue { /// Variant storage for a simple value. /// /// The variant can store a scalar, vector, or matrix value. -#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)] #[non_exhaustive] pub enum Value { /// Scalar value. diff --git a/src/lib.rs b/src/lib.rs index 2aaf9624..c1e885a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ //! //! App::default() //! .add_plugins(DefaultPlugins) -//! .add_plugin(HanabiPlugin) +//! .add_plugins(HanabiPlugin) //! .run(); //! ``` //! @@ -341,9 +341,7 @@ impl ToWgslString for Value { } /// Simulation space for the particles of an effect. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Eq, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Reflect, Serialize, Deserialize)] #[non_exhaustive] pub enum SimulationSpace { /// Particles are simulated in global space. @@ -362,7 +360,7 @@ pub enum SimulationSpace { /// /// A property with this name might not exist, in which case the value will be /// discarded silently when the instance is initialized from its asset. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[derive(Debug, Clone, PartialEq, Reflect)] pub struct PropertyValue { /// Name of the property the value should be assigned to. name: String, @@ -1164,6 +1162,7 @@ fn compile_effects( /// system, to clean-up unused GPU resources. /// /// [`extract_effects()`]: crate::render::extract_effects +#[derive(Event)] struct RemovedEffectsEvent { entities: Vec, } @@ -1334,14 +1333,13 @@ else { return c1; } // app.add_plugins(DefaultPlugins); app.add_asset::(); app.add_asset::(); - app.add_plugin(VisibilityPlugin); + app.add_plugins(VisibilityPlugin); app.init_resource::(); app.insert_resource(Random(new_rng())); app.add_asset::(); - app.add_system( - compile_effects - .in_base_set(CoreSet::PostUpdate) - .after(VisibilitySystems::CheckVisibility), + app.add_systems( + PostUpdate, + compile_effects.after(VisibilitySystems::CheckVisibility), ); app diff --git a/src/modifier/init.rs b/src/modifier/init.rs index 870fbb9c..12ed5cae 100644 --- a/src/modifier/init.rs +++ b/src/modifier/init.rs @@ -113,7 +113,7 @@ macro_rules! impl_mod_init { /// # Attributes /// /// This modifier requires the attribute specified in the `attribute` field. -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct InitAttributeModifier { /// The name of the attribute to initialize. pub attribute: Attribute, @@ -169,7 +169,7 @@ impl InitModifier for InitAttributeModifier { /// /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] -#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitPositionCircleModifier { /// The circle center, relative to the emitter position. pub center: Vec3, @@ -246,7 +246,7 @@ impl InitModifier for InitPositionCircleModifier { /// /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitPositionSphereModifier { /// The sphere center, relative to the emitter position. pub center: Vec3, @@ -321,7 +321,7 @@ impl InitModifier for InitPositionSphereModifier { /// /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitPositionCone3dModifier { /// The cone height along its axis, between the base and top radii. pub height: f32, @@ -389,7 +389,7 @@ impl InitModifier for InitPositionCone3dModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitVelocityCircleModifier { /// The circle center, relative to the emitter position. pub center: Vec3, @@ -437,7 +437,7 @@ impl InitModifier for InitVelocityCircleModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitVelocitySphereModifier { /// Center of the sphere. The radial direction of the velocity is the /// direction from the sphere center to the particle position. @@ -473,7 +473,7 @@ impl InitModifier for InitVelocitySphereModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitVelocityTangentModifier { /// Origin from which to derive the radial axis based on the particle /// position. @@ -526,7 +526,7 @@ impl InitModifier for InitVelocityTangentModifier { /// - [`Attribute::SIZE`] or [`Attribute::SIZE2`] /// /// [`SizeOverLifetimeModifier`]: crate::SizeOverLifetimeModifier -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct InitSizeModifier { /// The size to initialize each particle with. /// @@ -580,7 +580,7 @@ mod tests { use super::*; use crate::ParticleLayout; - use naga::front::wgsl::Parser; + use naga::front::wgsl::Frontend; #[test] fn validate() { @@ -632,8 +632,8 @@ fn main() {{ ); // println!("code: {:?}", code); - let mut parser = Parser::new(); - let res = parser.parse(&code); + let mut frontend = Frontend::new(); + let res = frontend.parse(&code); if let Err(err) = &res { println!("Modifier: {:?}", modifier.type_name()); println!("Code: {:?}", code); diff --git a/src/modifier/mod.rs b/src/modifier/mod.rs index a81935cc..dd18716b 100644 --- a/src/modifier/mod.rs +++ b/src/modifier/mod.rs @@ -22,7 +22,7 @@ //! [`UpdateModifier`]: crate::modifier::update::UpdateModifier //! [`RenderModifier`]: crate::modifier::render::RenderModifier -use bevy::reflect::{FromReflect, Reflect}; +use bevy::reflect::Reflect; use serde::{Deserialize, Serialize}; use std::{ collections::hash_map::DefaultHasher, @@ -42,9 +42,7 @@ use crate::{Attribute, Property}; /// The dimension of a shape to consider. /// /// The exact meaning depends on the context where this enum is used. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Eq, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Reflect, Serialize, Deserialize)] pub enum ShapeDimension { /// Consider the surface of the shape only. #[default] @@ -172,8 +170,8 @@ mod tests { let rm: &dyn Reflect = m.as_reflect(); let rm_serde: &dyn Reflect = m_serde.as_reflect(); assert_eq!( - rm.get_type_info().type_id(), - rm_serde.get_type_info().type_id() + rm.get_represented_type_info().unwrap().type_id(), + rm_serde.get_represented_type_info().unwrap().type_id() ); assert!(rm_serde.is::()); diff --git a/src/modifier/render.rs b/src/modifier/render.rs index 1d208e4f..ffc8d908 100644 --- a/src/modifier/render.rs +++ b/src/modifier/render.rs @@ -107,7 +107,7 @@ macro_rules! impl_mod_render { /// # Attributes /// /// This modifier does not require any specific particle attribute. -#[derive(Default, Debug, Clone, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Reflect, Serialize, Deserialize)] pub struct ParticleTextureModifier { /// The texture image to modulate the particle color with. #[serde(skip)] @@ -135,7 +135,7 @@ impl RenderModifier for ParticleTextureModifier { /// # Attributes /// /// This modifier does not require any specific particle attribute. -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct SetColorModifier { /// The particle color. pub color: Value, @@ -185,7 +185,7 @@ impl RenderModifier for SetColorModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::AGE`] /// - [`Attribute::LIFETIME`] -#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct ColorOverLifetimeModifier { /// The color gradient defining the particle color based on its lifetime. pub gradient: Gradient, @@ -228,7 +228,7 @@ impl RenderModifier for ColorOverLifetimeModifier { /// # Attributes /// /// This modifier does not require any specific particle attribute. -#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub struct SetSizeModifier { /// The particle color. pub size: Value, @@ -256,6 +256,7 @@ impl Hash for SetSizeModifier { FloatOrd(b.y).hash(state); } } + self.screen_space_size.hash(state); } } @@ -277,7 +278,7 @@ impl RenderModifier for SetSizeModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::AGE`] /// - [`Attribute::LIFETIME`] -#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct SizeOverLifetimeModifier { /// The size gradient defining the particle size based on its lifetime. pub gradient: Gradient, @@ -322,9 +323,7 @@ impl RenderModifier for SizeOverLifetimeModifier { /// # Attributes /// /// This modifier does not require any specific particle attribute. -#[derive( - Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct BillboardModifier; impl_mod_render!(BillboardModifier, &[]); @@ -343,9 +342,7 @@ impl RenderModifier for BillboardModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive( - Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct OrientAlongVelocityModifier; impl_mod_render!( @@ -370,7 +367,7 @@ mod tests { use super::*; - use naga::front::wgsl::Parser; + use naga::front::wgsl::Frontend; #[test] fn mod_particle_texture() { @@ -510,8 +507,8 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 {{ }}"## ); - let mut parser = Parser::new(); - let res = parser.parse(&code); + let mut frontend = Frontend::new(); + let res = frontend.parse(&code); if let Err(err) = &res { println!("Modifier: {:?}", modifier.type_name()); println!("Code: {:?}", code); diff --git a/src/modifier/update.rs b/src/modifier/update.rs index 8fb120e1..3875060b 100644 --- a/src/modifier/update.rs +++ b/src/modifier/update.rs @@ -107,7 +107,7 @@ macro_rules! impl_mod_update { /// This enumeration either directly stores a constant value assigned at /// creation time, or a reference to an effect property the value is derived /// from. -#[derive(Debug, Clone, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub enum ValueOrProperty { /// Constant value. Value(Value), @@ -151,7 +151,7 @@ impl ToWgslString for ValueOrProperty { /// /// This modifier requires the following particle attributes: /// - [`Attribute::VELOCITY`] -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct AccelModifier { /// The acceleration to apply to all particles in the effect each frame. accel: ExprHandle, @@ -246,7 +246,7 @@ impl UpdateModifier for AccelModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive(Debug, Clone, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Reflect, Serialize, Deserialize)] pub struct RadialAccelModifier { /// The acceleration to apply to all particles in the effect each frame. accel: ValueOrProperty, @@ -369,7 +369,7 @@ impl UpdateModifier for RadialAccelModifier { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive(Debug, Clone, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Reflect, Serialize, Deserialize)] pub struct TangentAccelModifier { /// The acceleration to apply to all particles in the effect each frame. accel: ValueOrProperty, @@ -490,7 +490,7 @@ impl UpdateModifier for TangentAccelModifier { /// position, with a decreasing intensity the further away from the source the /// particle is. This force is added to the one(s) of all the other active /// sources of a [`ForceFieldModifier`]. -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct ForceFieldSource { /// Position of the source. pub position: Vec3, @@ -573,9 +573,7 @@ impl ForceFieldSource { /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] /// - [`Attribute::VELOCITY`] -#[derive( - Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, FromReflect, Serialize, Deserialize, -)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)] pub struct ForceFieldModifier { /// Array of force field sources. /// @@ -664,7 +662,7 @@ impl UpdateModifier for ForceFieldModifier { /// /// This modifier requires the following particle attributes: /// - [`Attribute::VELOCITY`] -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct LinearDragModifier { /// Drag coefficient. Higher values increase the drag force, and /// consequently decrease the particle's speed faster. @@ -714,7 +712,7 @@ impl UpdateModifier for LinearDragModifier { /// /// This modifier requires the following particle attributes: /// - [`Attribute::POSITION`] -#[derive(Debug, Clone, Copy, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)] pub struct AabbKillModifier { /// Center of the AABB. pub center: ExprHandle, @@ -783,7 +781,7 @@ mod tests { use super::*; - use naga::front::wgsl::Parser; + use naga::front::wgsl::Frontend; #[test] fn mod_accel() { @@ -918,8 +916,8 @@ fn main() {{ }}"## ); - let mut parser = Parser::new(); - let res = parser.parse(&code); + let mut frontend = Frontend::new(); + let res = frontend.parse(&code); if let Err(err) = &res { println!("Modifier: {:?}", modifier.type_name()); println!("Code: {:?}", code); diff --git a/src/plugin.rs b/src/plugin.rs index 02cd0cba..e0f741e7 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -10,7 +10,7 @@ use bevy::{ render_resource::{SpecializedComputePipelines, SpecializedRenderPipelines}, renderer::{RenderAdapterInfo, RenderDevice}, view::visibility::VisibilitySystems, - RenderApp, RenderSet, + Render, RenderApp, RenderSet, }, }; @@ -51,47 +51,63 @@ pub struct HanabiPlugin; impl Plugin for HanabiPlugin { fn build(&self, app: &mut App) { - let render_device = app.world.get_resource::().unwrap().clone(); - - // Check device limits - let limits = render_device.limits(); - if limits.max_bind_groups < 4 { - let adapter_name = app - .world - .get_resource::() - .map(|ai| &ai.name[..]) - .unwrap_or(""); - error!("Hanabi requires a GPU device supporting at least 4 bind groups (Limits::max_bind_groups).\n Current adapter: {}\n Supported bind groups: {}", adapter_name, limits.max_bind_groups); - return; - } - // Register asset app.add_asset::() .add_event::() .insert_resource(Random(spawn::new_rng())) .init_resource::() .init_asset_loader::() - .configure_sets(( - EffectSystems::TickSpawners - .in_base_set(CoreSet::PostUpdate) - // This checks the visibility to skip work, so needs to run after - // ComputedVisibility was updated. - .after(VisibilitySystems::CheckVisibility), - EffectSystems::CompileEffects - .in_base_set(CoreSet::PostUpdate) - // This checks the visibility to skip work, so needs to run after - // ComputedVisibility was updated. - .after(VisibilitySystems::CheckVisibility), - EffectSystems::GatherRemovedEffects.in_base_set(CoreSet::PostUpdate), - )) - .add_system(tick_spawners.in_set(EffectSystems::TickSpawners)) - .add_system(compile_effects.in_set(EffectSystems::CompileEffects)) - .add_system(gather_removed_effects.in_set(EffectSystems::GatherRemovedEffects)); + .configure_sets( + PostUpdate, + ( + EffectSystems::TickSpawners + // This checks the visibility to skip work, so needs to run after + // ComputedVisibility was updated. + .after(VisibilitySystems::CheckVisibility), + EffectSystems::CompileEffects + // This checks the visibility to skip work, so needs to run after + // ComputedVisibility was updated. + .after(VisibilitySystems::CheckVisibility), + EffectSystems::GatherRemovedEffects, + ), + ) + .add_systems( + PostUpdate, + ( + tick_spawners.in_set(EffectSystems::TickSpawners), + compile_effects.in_set(EffectSystems::CompileEffects), + gather_removed_effects.in_set(EffectSystems::GatherRemovedEffects), + ), + ); // Register the component reflection app.register_type::(); app.register_type::(); app.register_type::(); + } + + fn finish(&self, app: &mut App) { + let render_device = app + .sub_app(RenderApp) + .world + .get_resource::() + .unwrap() + .clone(); + + let adapter_name = app + .world + .get_resource::() + .map(|ai| &ai.name[..]) + .unwrap_or(""); + + // Check device limits + let limits = render_device.limits(); + if limits.max_bind_groups < 4 { + error!("Hanabi requires a GPU device supporting at least 4 bind groups (Limits::max_bind_groups).\n Current adapter: {}\n Supported bind groups: {}", adapter_name, limits.max_bind_groups); + return; + } else { + info!("Initializing Hanabi for GPU adapter {}", adapter_name); + } let effects_meta = EffectsMeta::new(render_device); @@ -110,17 +126,23 @@ impl Plugin for HanabiPlugin { .init_resource::() .init_resource::() .init_resource::() - .configure_sets(( - EffectSystems::PrepareEffects.in_set(RenderSet::Prepare), - EffectSystems::QueueEffects.in_set(RenderSet::Queue), - )) + .configure_sets( + Render, + ( + EffectSystems::PrepareEffects.in_set(RenderSet::Prepare), + EffectSystems::QueueEffects.in_set(RenderSet::Queue), + ), + ) .edit_schedule(ExtractSchedule, |schedule| { - schedule - .add_system(extract_effects) - .add_system(extract_effect_events); + schedule.add_systems((extract_effects, extract_effect_events)); }) - .add_system(prepare_effects.in_set(EffectSystems::PrepareEffects)) - .add_system(queue_effects.in_set(EffectSystems::QueueEffects)); + .add_systems( + Render, + ( + prepare_effects.in_set(EffectSystems::PrepareEffects), + queue_effects.in_set(EffectSystems::QueueEffects), + ), + ); // Register the draw function for drawing the particles. This will be called // during the main 2D/3D pass, at the Transparent2d/3d phase, after the diff --git a/src/properties.rs b/src/properties.rs index bf1f51fe..1363d8d9 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -10,13 +10,13 @@ use std::num::NonZeroU64; -use bevy::reflect::{FromReflect, Reflect}; +use bevy::reflect::Reflect; use serde::{Deserialize, Serialize}; use crate::{graph::Value, next_multiple_of, ToWgslString, ValueType}; /// Effect property. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Reflect, Serialize, Deserialize)] pub struct Property { name: String, default_value: Value, @@ -79,7 +79,7 @@ impl ToWgslString for Property { /// Instance of a [`Property`] owned by a specific [`ParticleEffect`] component. /// /// [`ParticleEffect`]: crate::ParticleEffect -#[derive(Debug, Clone, Reflect, FromReflect)] +#[derive(Debug, Clone, Reflect)] pub(crate) struct PropertyInstance { /// The property definition, including its default value. pub def: Property, diff --git a/src/render/mod.rs b/src/render/mod.rs index 52f15cc9..74c72224 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -64,26 +64,23 @@ pub use shader_cache::ShaderCache; pub enum EffectSystems { /// Tick all effect instances to generate spawner counts. /// - /// This system runs during the [`CoreSet::PostUpdate`] set, in parallel of + /// This system runs during the [`PostUpdate`] set, in parallel of /// [`CompileEffects`]. /// - /// [`CoreSet::PostUpdate`]: bevy::app::CoreSet::PostUpdate /// [`CompileEffects`]: EffectSystems::CompileEffects TickSpawners, /// Compile the effect instances, updating the [`CompiledParticleEffect`] /// components. /// - /// This system runs during the [`CoreSet::PostUpdate`] set, in parallel of + /// This system runs during the [`PostUpdate`] set, in parallel of /// [`TickSpawners`]. /// - /// [`CoreSet::PostUpdate`]: bevy::app::CoreSet::PostUpdate /// [`TickSpawners`]: EffectSystems::TickSpawners CompileEffects, /// Gather all removed [`ParticleEffect`] components during the - /// [`CoreSet::PostUpdate`] set, to be able to clean-up GPU resources. + /// [`PostUpdate`] set, to be able to clean-up GPU resources. /// /// [`ParticleEffect`]: crate::ParticleEffect - /// [`CoreSet::PostUpdate`]: bevy::app::CoreSet::PostUpdate GatherRemovedEffects, /// Prepare GPU data for the extracted effects. PrepareEffects, @@ -1585,6 +1582,7 @@ const QUAD_VERTEX_POSITIONS: &[Vec3] = &[ ]; bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] struct LayoutFlags: u32 { const NONE = 0; const PARTICLE_TEXTURE = 0b00000001; @@ -2846,7 +2844,7 @@ impl Node for VfxSimulateDriverNode { _render_context: &mut RenderContext, _world: &World, ) -> Result<(), NodeRunError> { - graph.run_sub_graph(crate::plugin::simulate_graph::NAME, vec![])?; + graph.run_sub_graph(crate::plugin::simulate_graph::NAME, vec![], None)?; Ok(()) } } @@ -3042,7 +3040,7 @@ impl Node for VfxSimulateNode { ); compute_pass.dispatch_workgroups(workgroup_count, 1, 1); trace!( - "indirect dispatch compute dispatched: num_batches={} workgroup_count{}", + "indirect dispatch compute dispatched: num_batches={} workgroup_count={}", num_batches, workgroup_count ); diff --git a/src/render/shader_cache.rs b/src/render/shader_cache.rs index bc92312f..ae300553 100644 --- a/src/render/shader_cache.rs +++ b/src/render/shader_cache.rs @@ -1,3 +1,5 @@ +use std::hash::{Hash, Hasher}; + use bevy::{ asset::{Assets, Handle}, ecs::{change_detection::ResMut, system::Resource}, @@ -34,7 +36,13 @@ impl ShaderCache { if let Some(handle) = self.cache.get(source) { handle.clone() } else { - let handle = shaders.add(Shader::from_wgsl(source.to_string())); + let mut hasher = bevy::utils::AHasher::default(); + source.hash(&mut hasher); + let hash = hasher.finish(); + let handle = shaders.add(Shader::from_wgsl( + source.to_string(), + format!("hanabi/shader_{}.wgsl", hash), + )); debug!("Inserted new configured shader: {:?}\n{}", handle, source); self.cache.insert(source.to_string(), handle.clone()); handle diff --git a/src/render/vfx_render.wgsl b/src/render/vfx_render.wgsl index c6b5da5b..366356be 100644 --- a/src/render/vfx_render.wgsl +++ b/src/render/vfx_render.wgsl @@ -1,4 +1,6 @@ +// FIXME - Use imports to get exact types from Bevy directly + struct ColorGrading { exposure: f32, gamma: f32, @@ -8,6 +10,7 @@ struct ColorGrading { struct View { view_proj: mat4x4, + unjittered_view_proj: mat4x4, inverse_view_proj: mat4x4, view: mat4x4, inverse_view: mat4x4, @@ -17,26 +20,27 @@ struct View { // viewport(x_origin, y_origin, width, height) viewport: vec4, color_grading: ColorGrading, + mip_bias: f32, } struct Particle { {{ATTRIBUTES}} -}; +} struct ParticlesBuffer { particles: array, -}; +} struct IndirectBuffer { indices: array, -}; +} struct DispatchIndirect { x: u32, y: u32, z: u32, pong: u32, -}; +} struct VertexOutput { @builtin(position) position: vec4, @@ -44,7 +48,7 @@ struct VertexOutput { #ifdef PARTICLE_TEXTURE @location(1) uv: vec2, #endif -}; +} @group(0) @binding(0) var view: View; @group(1) @binding(0) var particle_buffer : ParticlesBuffer; diff --git a/src/spawn.rs b/src/spawn.rs index 1e5c399d..6641da9c 100644 --- a/src/spawn.rs +++ b/src/spawn.rs @@ -1,8 +1,4 @@ -use bevy::{ - ecs::system::Resource, - prelude::*, - reflect::{FromReflect, Reflect}, -}; +use bevy::{ecs::system::Resource, prelude::*, reflect::Reflect}; use rand::{ distributions::{uniform::SampleUniform, Distribution, Uniform}, SeedableRng, @@ -28,7 +24,7 @@ pub struct Random(pub Pcg32); /// /// This enum represents a value which is either constant, or randomly sampled /// according to a given probability distribution. -#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Reflect, FromReflect)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Reflect)] #[non_exhaustive] pub enum Value { /// Single constant value. @@ -94,7 +90,7 @@ impl From for Value { /// /// [`Attribute::SIZE`]: crate::Attribute::SIZE /// [`Attribute::SIZE2`]: crate::Attribute::SIZE2 -#[derive(Debug, Clone, Copy, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Reflect, Serialize, Deserialize)] pub enum DimValue { /// Scalar. D1(Value), @@ -156,7 +152,7 @@ impl ToWgslString for DimValue { /// particles and initialize them. The number of particles to spawn is stored as /// a floating-point number, and any remainder accumulates for the next /// emitting. -#[derive(Debug, Copy, Clone, PartialEq, Reflect, FromReflect, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Reflect, Serialize, Deserialize)] #[reflect(Default)] pub struct Spawner { /// Number of particles to spawn over [`spawn_time`]. @@ -474,7 +470,7 @@ impl EffectSpawner { /// the spawner calculates the number of particles to spawn. /// /// This method is called automatically by [`tick_spawners()`] during the - /// [`CoreSet::PostUpdate`], so you normally don't have to call it yourself + /// [`PostUpdate`], so you normally don't have to call it yourself /// manually. /// /// # Returns @@ -549,8 +545,8 @@ impl EffectSpawner { /// Tick all the spawners of the visible [`ParticleEffect`] components. /// -/// This system runs in the [`CoreSet::PostUpdate`] stage, after the visibility -/// system has updated the [`ComputedVisibility`] of each effect instance (see +/// This system runs in the [`PostUpdate`] stage, after the visibility system +/// has updated the [`ComputedVisibility`] of each effect instance (see /// [`VisibilitySystems::CheckVisibility`]). Hidden instances are not updated, /// unless the [`EffectAsset::simulation_condition`] is set to /// [`SimulationCondition::Always`]. @@ -771,14 +767,13 @@ mod test { app.insert_resource(asset_server); // app.add_plugins(DefaultPlugins); app.add_asset::(); - app.add_plugin(VisibilityPlugin); + app.add_plugins(VisibilityPlugin); app.init_resource::