diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79f8623d81990..ba2295b9ceefb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: env: CARGO_TERM_COLOR: always - NIGHTLY_TOOLCHAIN: nightly-2024-01-17 + NIGHTLY_TOOLCHAIN: nightly jobs: build: diff --git a/assets/scenes/load_scene_example.scn.ron b/assets/scenes/load_scene_example.scn.ron index c1c725c8d2ccd..6527acf87a1cf 100644 --- a/assets/scenes/load_scene_example.scn.ron +++ b/assets/scenes/load_scene_example.scn.ron @@ -5,7 +5,7 @@ ), }, entities: { - 0: ( + 4294967296: ( components: { "bevy_transform::components::transform::Transform": ( translation: ( @@ -34,7 +34,7 @@ ), }, ), - 1: ( + 4294967297: ( components: { "scene::ComponentA": ( x: 3.0, diff --git a/crates/bevy_asset/src/io/file/mod.rs b/crates/bevy_asset/src/io/file/mod.rs index 8aeff687d6c07..6ee59fab37d24 100644 --- a/crates/bevy_asset/src/io/file/mod.rs +++ b/crates/bevy_asset/src/io/file/mod.rs @@ -6,6 +6,7 @@ mod file_asset; #[cfg(not(feature = "multi-threaded"))] mod sync_file_asset; +use bevy_log::error; #[cfg(feature = "file_watcher")] pub use file_watcher::*; @@ -73,7 +74,15 @@ impl FileAssetWriter { /// watching for changes. /// /// See `get_base_path` below. - pub fn new>(path: P) -> Self { + pub fn new + std::fmt::Debug>(path: P, create_root: bool) -> Self { + if create_root { + if let Err(e) = std::fs::create_dir_all(&path) { + error!( + "Failed to create root directory {:?} for file asset writer: {:?}", + path, e + ); + } + } Self { root_path: get_base_path().join(path.as_ref()), } diff --git a/crates/bevy_asset/src/io/source.rs b/crates/bevy_asset/src/io/source.rs index a9f8adb8c17f3..57f6170d17b3e 100644 --- a/crates/bevy_asset/src/io/source.rs +++ b/crates/bevy_asset/src/io/source.rs @@ -111,7 +111,7 @@ impl<'a> PartialEq for AssetSourceId<'a> { #[derive(Default)] pub struct AssetSourceBuilder { pub reader: Option Box + Send + Sync>>, - pub writer: Option Option> + Send + Sync>>, + pub writer: Option Option> + Send + Sync>>, pub watcher: Option< Box< dyn FnMut(crossbeam_channel::Sender) -> Option> @@ -120,7 +120,8 @@ pub struct AssetSourceBuilder { >, >, pub processed_reader: Option Box + Send + Sync>>, - pub processed_writer: Option Option> + Send + Sync>>, + pub processed_writer: + Option Option> + Send + Sync>>, pub processed_watcher: Option< Box< dyn FnMut(crossbeam_channel::Sender) -> Option> @@ -142,8 +143,8 @@ impl AssetSourceBuilder { watch_processed: bool, ) -> Option { let reader = self.reader.as_mut()?(); - let writer = self.writer.as_mut().and_then(|w| w()); - let processed_writer = self.processed_writer.as_mut().and_then(|w| w()); + let writer = self.writer.as_mut().and_then(|w| w(false)); + let processed_writer = self.processed_writer.as_mut().and_then(|w| w(true)); let mut source = AssetSource { id: id.clone(), reader, @@ -200,7 +201,7 @@ impl AssetSourceBuilder { /// Will use the given `writer` function to construct unprocessed [`AssetWriter`] instances. pub fn with_writer( mut self, - writer: impl FnMut() -> Option> + Send + Sync + 'static, + writer: impl FnMut(bool) -> Option> + Send + Sync + 'static, ) -> Self { self.writer = Some(Box::new(writer)); self @@ -230,7 +231,7 @@ impl AssetSourceBuilder { /// Will use the given `writer` function to construct processed [`AssetWriter`] instances. pub fn with_processed_writer( mut self, - writer: impl FnMut() -> Option> + Send + Sync + 'static, + writer: impl FnMut(bool) -> Option> + Send + Sync + 'static, ) -> Self { self.processed_writer = Some(Box::new(writer)); self @@ -443,10 +444,13 @@ impl AssetSource { /// the asset root. This will return [`None`] if this platform does not support writing assets by default. pub fn get_default_writer( _path: String, - ) -> impl FnMut() -> Option> + Send + Sync { - move || { + ) -> impl FnMut(bool) -> Option> + Send + Sync { + move |_create_root: bool| { #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] - return Some(Box::new(super::file::FileAssetWriter::new(&_path))); + return Some(Box::new(super::file::FileAssetWriter::new( + &_path, + _create_root, + ))); #[cfg(any(target_arch = "wasm32", target_os = "android"))] return None; } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index aadccccf54fed..6d86737485bac 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -218,7 +218,8 @@ impl Plugin for AssetPlugin { UpdateAssets, TrackAssets.after(handle_internal_asset_events), ) - .add_systems(UpdateAssets, handle_internal_asset_events); + .add_systems(UpdateAssets, handle_internal_asset_events) + .register_type::(); let mut order = app.world.resource_mut::(); order.insert_after(First, UpdateAssets); diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 51cb399d10182..457f5c3940d8f 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -338,7 +338,7 @@ impl AssetServer { self.load_internal(None, path, false, None).await } - /// Load an asset without knowing it's type. The method returns a handle to a [`LoadedUntypedAsset`]. + /// Load an asset without knowing its type. The method returns a handle to a [`LoadedUntypedAsset`]. /// /// Once the [`LoadedUntypedAsset`] is loaded, an untyped handle for the requested path can be /// retrieved from it. diff --git a/crates/bevy_core/src/name.rs b/crates/bevy_core/src/name.rs index 1f6f40c7cec42..dfa4a11c118bd 100644 --- a/crates/bevy_core/src/name.rs +++ b/crates/bevy_core/src/name.rs @@ -10,6 +10,9 @@ use std::{ ops::Deref, }; +#[cfg(feature = "serialize")] +use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; + /// Component used to identify an entity. Stores a hash for faster comparisons. /// /// The hash is eagerly re-computed upon each update to the name. @@ -19,8 +22,9 @@ use std::{ /// used instead as the default unique identifier. #[derive(Reflect, Component, Clone)] #[reflect(Component, Default, Debug)] +#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))] pub struct Name { - hash: u64, // TODO: Shouldn't be serialized + hash: u64, // Won't be serialized (see: `bevy_core::serde` module) name: Cow<'static, str>, } diff --git a/crates/bevy_core_pipeline/src/bloom/mod.rs b/crates/bevy_core_pipeline/src/bloom/mod.rs index f9adf440f85ab..85f3e93ff1be1 100644 --- a/crates/bevy_core_pipeline/src/bloom/mod.rs +++ b/crates/bevy_core_pipeline/src/bloom/mod.rs @@ -113,7 +113,7 @@ impl Plugin for BloomPlugin { #[derive(Default)] struct BloomNode; impl ViewNode for BloomNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static ViewTarget, &'static BloomTexture, @@ -140,7 +140,7 @@ impl ViewNode for BloomNode { bloom_settings, upsampling_pipeline_ids, downsampling_pipeline_ids, - ): QueryItem, + ): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let downsampling_pipeline_res = world.resource::(); diff --git a/crates/bevy_core_pipeline/src/bloom/settings.rs b/crates/bevy_core_pipeline/src/bloom/settings.rs index a5514a9f9665b..69c789933c686 100644 --- a/crates/bevy_core_pipeline/src/bloom/settings.rs +++ b/crates/bevy_core_pipeline/src/bloom/settings.rs @@ -182,12 +182,12 @@ pub enum BloomCompositeMode { } impl ExtractComponent for BloomSettings { - type Data = (&'static Self, &'static Camera); + type QueryData = (&'static Self, &'static Camera); - type Filter = (); + type QueryFilter = (); type Out = (Self, BloomUniforms); - fn extract_component((settings, camera): QueryItem<'_, Self::Data>) -> Option { + fn extract_component((settings, camera): QueryItem<'_, Self::QueryData>) -> Option { match ( camera.physical_viewport_rect(), camera.physical_viewport_size(), diff --git a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs index af51d695eafa2..6e512b873572a 100644 --- a/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs +++ b/crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs @@ -77,11 +77,11 @@ pub struct CASUniform { } impl ExtractComponent for ContrastAdaptiveSharpeningSettings { - type Data = &'static Self; - type Filter = With; + type QueryData = &'static Self; + type QueryFilter = With; type Out = (DenoiseCAS, CASUniform); - fn extract_component(item: QueryItem) -> Option { + fn extract_component(item: QueryItem) -> Option { if !item.enabled || item.sharpening_strength == 0.0 { return None; } diff --git a/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs b/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs index 82ce6d9858fab..804f6afcf8e18 100644 --- a/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs +++ b/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs @@ -20,7 +20,7 @@ use super::AlphaMask3d; #[derive(Default)] pub struct MainOpaquePass3dNode; impl ViewNode for MainOpaquePass3dNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static RenderPhase, &'static RenderPhase, @@ -44,7 +44,7 @@ impl ViewNode for MainOpaquePass3dNode { skybox_pipeline, skybox_bind_group, view_uniform_offset, - ): QueryItem, + ): QueryItem, world: &World, ) -> Result<(), NodeRunError> { // Run the opaque pass, sorted front-to-back diff --git a/crates/bevy_core_pipeline/src/core_3d/main_transmissive_pass_3d_node.rs b/crates/bevy_core_pipeline/src/core_3d/main_transmissive_pass_3d_node.rs index 99ed34397e9cc..73a679ba047eb 100644 --- a/crates/bevy_core_pipeline/src/core_3d/main_transmissive_pass_3d_node.rs +++ b/crates/bevy_core_pipeline/src/core_3d/main_transmissive_pass_3d_node.rs @@ -18,7 +18,7 @@ use std::ops::Range; pub struct MainTransmissivePass3dNode; impl ViewNode for MainTransmissivePass3dNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static Camera3d, &'static RenderPhase, @@ -32,7 +32,7 @@ impl ViewNode for MainTransmissivePass3dNode { graph: &mut RenderGraphContext, render_context: &mut RenderContext, (camera, camera_3d, transmissive_phase, target, transmission, depth): QueryItem< - Self::ViewData, + Self::ViewQuery, >, world: &World, ) -> Result<(), NodeRunError> { diff --git a/crates/bevy_core_pipeline/src/core_3d/main_transparent_pass_3d_node.rs b/crates/bevy_core_pipeline/src/core_3d/main_transparent_pass_3d_node.rs index ba379edb0dcdf..1ffb059007c8f 100644 --- a/crates/bevy_core_pipeline/src/core_3d/main_transparent_pass_3d_node.rs +++ b/crates/bevy_core_pipeline/src/core_3d/main_transparent_pass_3d_node.rs @@ -16,7 +16,7 @@ use bevy_utils::tracing::info_span; pub struct MainTransparentPass3dNode; impl ViewNode for MainTransparentPass3dNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static RenderPhase, &'static ViewTarget, @@ -26,7 +26,7 @@ impl ViewNode for MainTransparentPass3dNode { &self, graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (camera, transparent_phase, target, depth): QueryItem, + (camera, transparent_phase, target, depth): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let view_entity = graph.view_entity(); diff --git a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs index aaf8d079dbec0..8d9bc3470c099 100644 --- a/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs +++ b/crates/bevy_core_pipeline/src/deferred/copy_lighting_id.rs @@ -61,7 +61,7 @@ impl CopyDeferredLightingIdNode { } impl ViewNode for CopyDeferredLightingIdNode { - type ViewData = ( + type ViewQuery = ( &'static ViewTarget, &'static ViewPrepassTextures, &'static DeferredLightingIdDepthTexture, @@ -72,7 +72,7 @@ impl ViewNode for CopyDeferredLightingIdNode { _graph: &mut RenderGraphContext, render_context: &mut RenderContext, (_view_target, view_prepass_textures, deferred_lighting_id_depth_texture): QueryItem< - Self::ViewData, + Self::ViewQuery, >, world: &World, ) -> Result<(), NodeRunError> { diff --git a/crates/bevy_core_pipeline/src/deferred/node.rs b/crates/bevy_core_pipeline/src/deferred/node.rs index 0df8875e0a3bb..95dcfc8ba76b3 100644 --- a/crates/bevy_core_pipeline/src/deferred/node.rs +++ b/crates/bevy_core_pipeline/src/deferred/node.rs @@ -25,7 +25,7 @@ use super::{AlphaMask3dDeferred, Opaque3dDeferred}; pub struct DeferredGBufferPrepassNode; impl ViewNode for DeferredGBufferPrepassNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static RenderPhase, &'static RenderPhase, @@ -43,7 +43,7 @@ impl ViewNode for DeferredGBufferPrepassNode { alpha_mask_deferred_phase, view_depth_texture, view_prepass_textures, - ): QueryItem, + ): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let view_entity = graph.view_entity(); diff --git a/crates/bevy_core_pipeline/src/fxaa/node.rs b/crates/bevy_core_pipeline/src/fxaa/node.rs index 954a8975d52be..9c920d5d59f98 100644 --- a/crates/bevy_core_pipeline/src/fxaa/node.rs +++ b/crates/bevy_core_pipeline/src/fxaa/node.rs @@ -20,7 +20,7 @@ pub struct FxaaNode { } impl ViewNode for FxaaNode { - type ViewData = ( + type ViewQuery = ( &'static ViewTarget, &'static CameraFxaaPipeline, &'static Fxaa, @@ -30,7 +30,7 @@ impl ViewNode for FxaaNode { &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (target, pipeline, fxaa): QueryItem, + (target, pipeline, fxaa): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let pipeline_cache = world.resource::(); diff --git a/crates/bevy_core_pipeline/src/prepass/node.rs b/crates/bevy_core_pipeline/src/prepass/node.rs index c37af2110a360..baaed25bd2871 100644 --- a/crates/bevy_core_pipeline/src/prepass/node.rs +++ b/crates/bevy_core_pipeline/src/prepass/node.rs @@ -22,7 +22,7 @@ use super::{AlphaMask3dPrepass, DeferredPrepass, Opaque3dPrepass, ViewPrepassTex pub struct PrepassNode; impl ViewNode for PrepassNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static RenderPhase, &'static RenderPhase, @@ -42,7 +42,7 @@ impl ViewNode for PrepassNode { view_depth_texture, view_prepass_textures, deferred_prepass, - ): QueryItem, + ): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let view_entity = graph.view_entity(); diff --git a/crates/bevy_core_pipeline/src/skybox/mod.rs b/crates/bevy_core_pipeline/src/skybox/mod.rs index c12b25351968c..ad0794f4ee568 100644 --- a/crates/bevy_core_pipeline/src/skybox/mod.rs +++ b/crates/bevy_core_pipeline/src/skybox/mod.rs @@ -80,12 +80,12 @@ pub struct Skybox { } impl ExtractComponent for Skybox { - type Data = (&'static Self, Option<&'static ExposureSettings>); - type Filter = (); + type QueryData = (&'static Self, Option<&'static ExposureSettings>); + type QueryFilter = (); type Out = (Self, SkyboxUniforms); fn extract_component( - (skybox, exposure_settings): QueryItem<'_, Self::Data>, + (skybox, exposure_settings): QueryItem<'_, Self::QueryData>, ) -> Option { let exposure = exposure_settings .map(|e| e.exposure()) diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index f322571d0c6b6..b0eb4f3057e69 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -168,7 +168,7 @@ impl Default for TemporalAntiAliasSettings { pub struct TemporalAntiAliasNode; impl ViewNode for TemporalAntiAliasNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static ViewTarget, &'static TemporalAntiAliasHistoryTextures, @@ -181,7 +181,7 @@ impl ViewNode for TemporalAntiAliasNode { _graph: &mut RenderGraphContext, render_context: &mut RenderContext, (camera, view_target, taa_history_textures, prepass_textures, taa_pipeline_id): QueryItem< - Self::ViewData, + Self::ViewQuery, >, world: &World, ) -> Result<(), NodeRunError> { diff --git a/crates/bevy_core_pipeline/src/tonemapping/node.rs b/crates/bevy_core_pipeline/src/tonemapping/node.rs index 49b6959b3c92a..08084592c013d 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/node.rs +++ b/crates/bevy_core_pipeline/src/tonemapping/node.rs @@ -24,7 +24,7 @@ pub struct TonemappingNode { } impl ViewNode for TonemappingNode { - type ViewData = ( + type ViewQuery = ( &'static ViewUniformOffset, &'static ViewTarget, &'static ViewTonemappingPipeline, @@ -36,7 +36,7 @@ impl ViewNode for TonemappingNode { _graph: &mut RenderGraphContext, render_context: &mut RenderContext, (view_uniform_offset, target, view_tonemapping_pipeline, tonemapping): QueryItem< - Self::ViewData, + Self::ViewQuery, >, world: &World, ) -> Result<(), NodeRunError> { diff --git a/crates/bevy_core_pipeline/src/upscaling/node.rs b/crates/bevy_core_pipeline/src/upscaling/node.rs index 5192e87f47f0d..16e277aeb0870 100644 --- a/crates/bevy_core_pipeline/src/upscaling/node.rs +++ b/crates/bevy_core_pipeline/src/upscaling/node.rs @@ -18,7 +18,7 @@ pub struct UpscalingNode { } impl ViewNode for UpscalingNode { - type ViewData = ( + type ViewQuery = ( &'static ViewTarget, &'static ViewUpscalingPipeline, Option<&'static ExtractedCamera>, @@ -28,7 +28,7 @@ impl ViewNode for UpscalingNode { &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (target, upscaling_target, camera): QueryItem, + (target, upscaling_target, camera): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let pipeline_cache = world.get_resource::().unwrap(); diff --git a/crates/bevy_ecs/src/reflect/entity_commands.rs b/crates/bevy_ecs/src/reflect/entity_commands.rs index 2e0f6495581a5..ae59cd1e33f66 100644 --- a/crates/bevy_ecs/src/reflect/entity_commands.rs +++ b/crates/bevy_ecs/src/reflect/entity_commands.rs @@ -140,7 +140,7 @@ pub trait ReflectCommandExt { ) -> &mut Self; } -impl<'w, 's, 'a> ReflectCommandExt for EntityCommands<'w, 's, 'a> { +impl ReflectCommandExt for EntityCommands<'_> { fn insert_reflect(&mut self, component: Box) -> &mut Self { self.commands.add(InsertReflect { entity: self.entity, diff --git a/crates/bevy_ecs/src/storage/blob_vec.rs b/crates/bevy_ecs/src/storage/blob_vec.rs index e8cf7c074b689..8636ac90383c0 100644 --- a/crates/bevy_ecs/src/storage/blob_vec.rs +++ b/crates/bevy_ecs/src/storage/blob_vec.rs @@ -124,6 +124,23 @@ impl BlobVec { } } + /// Reserves the minimum capacity for at least `additional` more elements to be inserted in the given `BlobVec`. + #[inline] + pub fn reserve(&mut self, additional: usize) { + /// Similar to `reserve_exact`. This method ensures that the capacity will grow at least `self.capacity()` if there is no + /// enough space to hold `additional` more elements. + #[cold] + fn do_reserve(slf: &mut BlobVec, additional: usize) { + let increment = slf.capacity.max(additional - (slf.capacity - slf.len)); + let increment = NonZeroUsize::new(increment).unwrap(); + slf.grow_exact(increment); + } + + if self.capacity - self.len < additional { + do_reserve(self, additional); + } + } + /// Grows the capacity by `increment` elements. /// /// # Panics @@ -241,7 +258,7 @@ impl BlobVec { /// The `value` must match the [`layout`](`BlobVec::layout`) of the elements in the [`BlobVec`]. #[inline] pub unsafe fn push(&mut self, value: OwningPtr<'_>) { - self.reserve_exact(1); + self.reserve(1); let index = self.len; self.len += 1; self.initialize_unchecked(index, value); @@ -530,7 +547,7 @@ mod tests { } assert_eq!(blob_vec.len(), 1_000); - assert_eq!(blob_vec.capacity(), 1_000); + assert_eq!(blob_vec.capacity(), 1_024); } #[derive(Debug, Eq, PartialEq, Clone)] @@ -590,19 +607,19 @@ mod tests { push(&mut blob_vec, foo3.clone()); assert_eq!(blob_vec.len(), 3); - assert_eq!(blob_vec.capacity(), 3); + assert_eq!(blob_vec.capacity(), 4); let last_index = blob_vec.len() - 1; let value = swap_remove::(&mut blob_vec, last_index); assert_eq!(foo3, value); assert_eq!(blob_vec.len(), 2); - assert_eq!(blob_vec.capacity(), 3); + assert_eq!(blob_vec.capacity(), 4); let value = swap_remove::(&mut blob_vec, 0); assert_eq!(foo1, value); assert_eq!(blob_vec.len(), 1); - assert_eq!(blob_vec.capacity(), 3); + assert_eq!(blob_vec.capacity(), 4); foo2.a = 8; assert_eq!(get_mut::(&mut blob_vec, 0), &foo2); diff --git a/crates/bevy_ecs/src/system/commands/command_queue.rs b/crates/bevy_ecs/src/system/commands/command_queue.rs index 5130089cc8fd2..0e372c6038358 100644 --- a/crates/bevy_ecs/src/system/commands/command_queue.rs +++ b/crates/bevy_ecs/src/system/commands/command_queue.rs @@ -1,4 +1,4 @@ -use std::mem::MaybeUninit; +use std::{fmt::Debug, mem::MaybeUninit}; use bevy_ptr::{OwningPtr, Unaligned}; use bevy_utils::tracing::warn; @@ -34,6 +34,19 @@ pub struct CommandQueue { bytes: Vec>, } +// CommandQueue needs to implement Debug manually, rather than deriving it, because the derived impl just prints +// [core::mem::maybe_uninit::MaybeUninit, core::mem::maybe_uninit::MaybeUninit, ..] for every byte in the vec, +// which gets extremely verbose very quickly, while also providing no useful information. +// It is not possible to soundly print the values of the contained bytes, as some of them may be padding or uninitialized (#4863) +// So instead, the manual impl just prints the length of vec. +impl Debug for CommandQueue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CommandQueue") + .field("len_bytes", &self.bytes.len()) + .finish_non_exhaustive() + } +} + // SAFETY: All commands [`Command`] implement [`Send`] unsafe impl Send for CommandQueue {} diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index cd62763fa6376..d2ebdce1a06f6 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -146,6 +146,31 @@ impl<'w, 's> Commands<'w, 's> { } } + /// Returns a [`Commands`] with a smaller lifetime. + /// This is useful if you have `&mut Commands` but need `Commands`. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// fn my_system(mut commands: Commands) { + /// // We do our initialization in a separate function, + /// // which expects an owned `Commands`. + /// do_initialization(commands.reborrow()); + /// + /// // Since we only reborrowed the commands instead of moving them, we can still use them. + /// commands.spawn_empty(); + /// } + /// # + /// # fn do_initialization(_: Commands) {} + /// ``` + pub fn reborrow(&mut self) -> Commands<'w, '_> { + Commands { + queue: self.queue.reborrow(), + entities: self.entities, + } + } + /// Take all commands from `other` and append them to `self`, leaving `other` empty pub fn append(&mut self, other: &mut CommandQueue) { self.queue.append(other); @@ -186,11 +211,11 @@ impl<'w, 's> Commands<'w, 's> { /// /// - [`spawn`](Self::spawn) to spawn an entity with a bundle. /// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each. - pub fn spawn_empty<'a>(&'a mut self) -> EntityCommands<'w, 's, 'a> { + pub fn spawn_empty(&mut self) -> EntityCommands { let entity = self.entities.reserve_entity(); EntityCommands { entity, - commands: self, + commands: self.reborrow(), } } @@ -208,13 +233,13 @@ impl<'w, 's> Commands<'w, 's> { /// [`Commands::spawn`]. This method should generally only be used for sharing entities across /// apps, and only when they have a scheme worked out to share an ID space (which doesn't happen /// by default). - pub fn get_or_spawn<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> { + pub fn get_or_spawn(&mut self, entity: Entity) -> EntityCommands { self.add(move |world: &mut World| { world.get_or_spawn(entity); }); EntityCommands { entity, - commands: self, + commands: self.reborrow(), } } @@ -268,7 +293,7 @@ impl<'w, 's> Commands<'w, 's> { /// /// - [`spawn_empty`](Self::spawn_empty) to spawn an entity without any components. /// - [`spawn_batch`](Self::spawn_batch) to spawn entities with a bundle each. - pub fn spawn<'a, T: Bundle>(&'a mut self, bundle: T) -> EntityCommands<'w, 's, 'a> { + pub fn spawn(&mut self, bundle: T) -> EntityCommands { let mut e = self.spawn_empty(); e.insert(bundle); e @@ -310,7 +335,7 @@ impl<'w, 's> Commands<'w, 's> { /// - [`get_entity`](Self::get_entity) for the fallible version. #[inline] #[track_caller] - pub fn entity<'a>(&'a mut self, entity: Entity) -> EntityCommands<'w, 's, 'a> { + pub fn entity(&mut self, entity: Entity) -> EntityCommands { #[inline(never)] #[cold] #[track_caller] @@ -359,10 +384,10 @@ impl<'w, 's> Commands<'w, 's> { /// - [`entity`](Self::entity) for the panicking version. #[inline] #[track_caller] - pub fn get_entity<'a>(&'a mut self, entity: Entity) -> Option> { + pub fn get_entity(&mut self, entity: Entity) -> Option { self.entities.contains(entity).then_some(EntityCommands { entity, - commands: self, + commands: self.reborrow(), }) } @@ -674,12 +699,12 @@ where } /// A list of commands that will be run to modify an [entity](crate::entity). -pub struct EntityCommands<'w, 's, 'a> { +pub struct EntityCommands<'a> { pub(crate) entity: Entity, - pub(crate) commands: &'a mut Commands<'w, 's>, + pub(crate) commands: Commands<'a, 'a>, } -impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { +impl EntityCommands<'_> { /// Returns the [`Entity`] id of the entity. /// /// # Example @@ -698,6 +723,15 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { self.entity } + /// Returns an [`EntityCommands`] with a smaller lifetime. + /// This is useful if you have `&mut EntityCommands` but you need `EntityCommands`. + pub fn reborrow(&mut self) -> EntityCommands { + EntityCommands { + entity: self.entity, + commands: self.commands.reborrow(), + } + } + /// Adds a [`Bundle`] of components to the entity. /// /// This will overwrite any previous value(s) of the same component type. @@ -956,8 +990,8 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { } /// Returns the underlying [`Commands`]. - pub fn commands(&mut self) -> &mut Commands<'w, 's> { - self.commands + pub fn commands(&mut self) -> Commands { + self.commands.reborrow() } } diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index a3d5872c8a123..8168654e18749 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -36,6 +36,35 @@ use std::{ /// Derived `SystemParam` structs may have two lifetimes: `'w` for data stored in the [`World`], /// and `'s` for data stored in the parameter's state. /// +/// The following list shows the most common [`SystemParam`]s and which lifetime they require +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// # #[derive(Resource)] +/// # struct SomeResource; +/// # #[derive(Event)] +/// # struct SomeEvent; +/// # #[derive(Resource)] +/// # struct SomeOtherResource; +/// # use bevy_ecs::system::SystemParam; +/// # #[derive(SystemParam)] +/// # struct ParamsExample<'w, 's> { +/// # query: +/// Query<'w, 's, Entity>, +/// # res: +/// Res<'w, SomeResource>, +/// # res_mut: +/// ResMut<'w, SomeOtherResource>, +/// # local: +/// Local<'s, u8>, +/// # commands: +/// Commands<'w, 's>, +/// # eventreader: +/// EventReader<'w, 's, SomeEvent>, +/// # eventwriter: +/// EventWriter<'w, SomeEvent> +/// # } +///``` /// ## `PhantomData` /// /// [`PhantomData`] is a special type of `SystemParam` that does nothing. @@ -890,6 +919,14 @@ impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> { } } +impl Deferred<'_, T> { + /// Returns a [`Deferred`] with a smaller lifetime. + /// This is useful if you have `&mut Deferred` but need `Deferred`. + pub fn reborrow(&mut self) -> Deferred { + Deferred(self.0) + } +} + // SAFETY: Only local state is accessed. unsafe impl ReadOnlySystemParam for Deferred<'_, T> {} diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 1bb0e74d0b04f..346e2244872e6 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1331,7 +1331,7 @@ impl World { pub fn get_resource(&self) -> Option<&R> { // SAFETY: // - `as_unsafe_world_cell_readonly` gives permission to access everything immutably - // - `&self` ensures nothing in world is borrowed immutably + // - `&self` ensures nothing in world is borrowed mutably unsafe { self.as_unsafe_world_cell_readonly().get_resource() } } diff --git a/crates/bevy_gizmos/src/circles.rs b/crates/bevy_gizmos/src/circles.rs index 9c218fe3ab5c1..2143996907ddb 100644 --- a/crates/bevy_gizmos/src/circles.rs +++ b/crates/bevy_gizmos/src/circles.rs @@ -4,7 +4,7 @@ //! and assorted support items. use crate::prelude::{GizmoConfigGroup, Gizmos}; -use bevy_math::{Quat, Vec2, Vec3}; +use bevy_math::{primitives::Direction3d, Quat, Vec2, Vec3}; use bevy_render::color::Color; use std::f32::consts::TAU; @@ -28,12 +28,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { /// # use bevy_render::prelude::*; /// # use bevy_math::prelude::*; /// fn system(mut gizmos: Gizmos) { - /// gizmos.circle(Vec3::ZERO, Vec3::Z, 1., Color::GREEN); + /// gizmos.circle(Vec3::ZERO, Direction3d::Z, 1., Color::GREEN); /// /// // Circles have 32 line-segments by default. /// // You may want to increase this for larger circles. /// gizmos - /// .circle(Vec3::ZERO, Vec3::Z, 5., Color::RED) + /// .circle(Vec3::ZERO, Direction3d::Z, 5., Color::RED) /// .segments(64); /// } /// # bevy_ecs::system::assert_is_system(system); @@ -42,7 +42,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { pub fn circle( &mut self, position: Vec3, - normal: Vec3, + normal: Direction3d, radius: f32, color: Color, ) -> CircleBuilder<'_, 'w, 's, T> { @@ -97,7 +97,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> { pub struct CircleBuilder<'a, 'w, 's, T: GizmoConfigGroup> { gizmos: &'a mut Gizmos<'w, 's, T>, position: Vec3, - normal: Vec3, + normal: Direction3d, radius: f32, color: Color, segments: usize, @@ -116,7 +116,7 @@ impl Drop for CircleBuilder<'_, '_, '_, T> { if !self.gizmos.enabled { return; } - let rotation = Quat::from_rotation_arc(Vec3::Z, self.normal); + let rotation = Quat::from_rotation_arc(Vec3::Z, *self.normal); let positions = circle_inner(self.radius, self.segments) .map(|vec2| self.position + rotation * vec2.extend(0.)); self.gizmos.linestrip(positions, self.color); diff --git a/crates/bevy_gizmos/src/gizmos.rs b/crates/bevy_gizmos/src/gizmos.rs index f4541b7f509e6..b9c0662879d1c 100644 --- a/crates/bevy_gizmos/src/gizmos.rs +++ b/crates/bevy_gizmos/src/gizmos.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam}, world::{unsafe_world_cell::UnsafeWorldCell, World}, }; -use bevy_math::{Mat2, Quat, Vec2, Vec3}; +use bevy_math::{primitives::Direction3d, Mat2, Quat, Vec2, Vec3}; use bevy_render::color::Color; use bevy_transform::TransformPoint; @@ -618,7 +618,12 @@ impl Drop for SphereBuilder<'_, '_, '_, T> { } for axis in Vec3::AXES { self.gizmos - .circle(self.position, self.rotation * axis, self.radius, self.color) + .circle( + self.position, + Direction3d::new_unchecked(self.rotation * axis), + self.radius, + self.color, + ) .segments(self.circle_segments); } } diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 684c4ddd29c4e..8696477ac7e41 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -343,14 +343,14 @@ fn prepare_line_gizmo_bind_group( struct SetLineGizmoBindGroup; impl RenderCommand

for SetLineGizmoBindGroup { type Param = SRes; - type ViewData = (); - type ItemData = Read>; + type ViewQuery = (); + type ItemQuery = Read>; #[inline] fn render<'w>( _item: &P, - _view: ROQueryItem<'w, Self::ViewData>, - uniform_index: ROQueryItem<'w, Self::ItemData>, + _view: ROQueryItem<'w, Self::ViewQuery>, + uniform_index: ROQueryItem<'w, Self::ItemQuery>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -366,14 +366,14 @@ impl RenderCommand

for SetLineGizmoBindGroup struct DrawLineGizmo; impl RenderCommand

for DrawLineGizmo { type Param = SRes>; - type ViewData = (); - type ItemData = Read>; + type ViewQuery = (); + type ItemQuery = Read>; #[inline] fn render<'w>( _item: &P, - _view: ROQueryItem<'w, Self::ViewData>, - handle: ROQueryItem<'w, Self::ItemData>, + _view: ROQueryItem<'w, Self::ViewQuery>, + handle: ROQueryItem<'w, Self::ItemQuery>, line_gizmos: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index d80c44c29e5e9..d119afe95ee70 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -274,15 +274,15 @@ impl Command for RemoveParent { /// }); /// # } /// ``` -pub struct ChildBuilder<'w, 's, 'a> { - commands: &'a mut Commands<'w, 's>, +pub struct ChildBuilder<'a> { + commands: Commands<'a, 'a>, push_children: PushChildren, } -impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { +impl ChildBuilder<'_> { /// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`]. /// Also adds [`Parent`] component to the created entity. - pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> { + pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands { let e = self.commands.spawn(bundle); self.push_children.children.push(e.id()); e @@ -290,7 +290,7 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { /// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`]. /// Also adds [`Parent`] component to the created entity. - pub fn spawn_empty(&mut self) -> EntityCommands<'w, 's, '_> { + pub fn spawn_empty(&mut self) -> EntityCommands { let e = self.commands.spawn_empty(); self.push_children.children.push(e.id()); e @@ -302,7 +302,7 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { } /// Adds a command to be executed, like [`Commands::add`]. - pub fn add_command(&mut self, command: C) -> &mut Self { + pub fn add_command(&mut self, command: C) -> &mut Self { self.commands.add(command); self } @@ -374,7 +374,7 @@ pub trait BuildChildren { fn remove_parent(&mut self) -> &mut Self; } -impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { +impl BuildChildren for EntityCommands<'_> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { let parent = self.id(); let mut builder = ChildBuilder { diff --git a/crates/bevy_hierarchy/src/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs index 817b5e14c5d86..d707be839c76f 100644 --- a/crates/bevy_hierarchy/src/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -89,7 +89,7 @@ pub trait DespawnRecursiveExt { fn despawn_descendants(&mut self) -> &mut Self; } -impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> { +impl DespawnRecursiveExt for EntityCommands<'_> { /// Despawns the provided entity and its children. fn despawn_recursive(mut self) { let entity = self.id(); diff --git a/crates/bevy_input/Cargo.toml b/crates/bevy_input/Cargo.toml index 4292633430b63..28a8c57ee8009 100644 --- a/crates/bevy_input/Cargo.toml +++ b/crates/bevy_input/Cargo.toml @@ -25,6 +25,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.12.0", features = [ # other serde = { version = "1", features = ["derive"], optional = true } thiserror = "1.0" +smol_str = "0.2" [dev-dependencies] bevy = { path = "../../", version = "0.12.0" } diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 8b7b784db259c..3465403871f45 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -73,6 +73,7 @@ use bevy_ecs::{ system::ResMut, }; use bevy_reflect::Reflect; +use smol_str::SmolStr; #[cfg(feature = "serialize")] use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; @@ -86,7 +87,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// /// The event is consumed inside of the [`keyboard_input_system`] /// to update the [`Input`](ButtonInput) resource. -#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect)] +#[derive(Event, Debug, Clone, PartialEq, Eq, Reflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( feature = "serialize", @@ -94,8 +95,10 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; reflect(Serialize, Deserialize) )] pub struct KeyboardInput { - /// The key code of the key. + /// The physical key code of the key. pub key_code: KeyCode, + /// The logical key of the input + pub logical_key: Key, /// The press state of the key. pub state: ButtonState, /// Window that received the input. @@ -650,3 +653,791 @@ pub enum KeyCode { /// General-purpose function key. F35, } + +/// Contains the platform-native logical key identifier, known as keysym. +/// +/// Exactly what that means differs from platform to platform, but the values are to some degree +/// tied to the currently active keyboard layout. The same key on the same keyboard may also report +/// different values on different platforms, which is one of the reasons this is a per-platform +/// enum. +/// +/// This enum is primarily used to store raw keysym when Winit doesn't map a given native logical +/// key identifier to a meaningful [`Key`] variant. This lets you use [`Key`], and let the user +/// define keybinds which work in the presence of identifiers we haven't mapped for you yet. +#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Hash, Reflect)] +#[reflect(Debug, Hash, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub enum NativeKey { + /// Unidentified + Unidentified, + /// An Android "keycode", which is similar to a "virtual-key code" on Windows. + Android(u32), + /// A macOS "scancode". There does not appear to be any direct analogue to either keysyms or + /// "virtual-key" codes in macOS, so we report the scancode instead. + MacOS(u16), + /// A Windows "virtual-key code". + Windows(u16), + /// An XKB "keysym". + Xkb(u32), + /// A "key value string". + Web(SmolStr), +} + +/// The logical key code of a [`KeyboardInput`]. +/// +/// ## Technical +/// +/// Its values map 1 to 1 to winit's Key. +#[non_exhaustive] +#[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Reflect)] +#[reflect(Debug, Hash, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub enum Key { + /// A key string that corresponds to the character typed by the user, taking into account the + /// user’s current locale setting, and any system-level keyboard mapping overrides that are in + /// effect. + Character(SmolStr), + + /// This variant is used when the key cannot be translated to any other variant. + /// + /// The native key is provided (if available) in order to allow the user to specify keybindings + /// for keys which are not defined by this API, mainly through some sort of UI. + Unidentified(NativeKey), + + /// Contains the text representation of the dead-key when available. + /// + /// ## Platform-specific + /// - **Web:** Always contains `None` + Dead(Option), + + /// The `Alt` (Alternative) key. + /// + /// This key enables the alternate modifier function for interpreting concurrent or subsequent + /// keyboard input. This key value is also used for the Apple Option key. + Alt, + /// The Alternate Graphics (AltGr or AltGraph) key. + /// + /// This key is used enable the ISO Level 3 shift modifier (the standard `Shift` key is the + /// level 2 modifier). + AltGraph, + /// The `Caps Lock` (Capital) key. + /// + /// Toggle capital character lock function for interpreting subsequent keyboard input event. + CapsLock, + /// The `Control` or `Ctrl` key. + /// + /// Used to enable control modifier function for interpreting concurrent or subsequent keyboard + /// input. + Control, + /// The Function switch `Fn` key. Activating this key simultaneously with another key changes + /// that key’s value to an alternate character or function. This key is often handled directly + /// in the keyboard hardware and does not usually generate key events. + Fn, + /// The Function-Lock (`FnLock` or `F-Lock`) key. Activating this key switches the mode of the + /// keyboard to changes some keys' values to an alternate character or function. This key is + /// often handled directly in the keyboard hardware and does not usually generate key events. + FnLock, + /// The `NumLock` or Number Lock key. Used to toggle numpad mode function for interpreting + /// subsequent keyboard input. + NumLock, + /// Toggle between scrolling and cursor movement modes. + ScrollLock, + /// Used to enable shift modifier function for interpreting concurrent or subsequent keyboard + /// input. + Shift, + /// The Symbol modifier key (used on some virtual keyboards). + Symbol, + /// The SymbolLock key, only on web. + SymbolLock, + /// Legacy modifier key. Also called "Super" in certain places. + Meta, + /// Legacy modifier key. + Hyper, + /// Used to enable "super" modifier function for interpreting concurrent or subsequent keyboard + /// input. This key value is used for the "Windows Logo" key and the Apple `Command` or `⌘` key. + /// + /// Note: In some contexts (e.g. the Web) this is referred to as the "Meta" key. + Super, + /// The `Enter` or `↵` key. Used to activate current selection or accept current input. This key + /// value is also used for the `Return` (Macintosh numpad) key. This key value is also used for + /// the Android `KEYCODE_DPAD_CENTER`. + Enter, + /// The Horizontal Tabulation `Tab` key. + Tab, + /// Used in text to insert a space between words. Usually located below the character keys. + Space, + /// Navigate or traverse downward. (`KEYCODE_DPAD_DOWN`) + ArrowDown, + /// Navigate or traverse leftward. (`KEYCODE_DPAD_LEFT`) + ArrowLeft, + /// Navigate or traverse rightward. (`KEYCODE_DPAD_RIGHT`) + ArrowRight, + /// Navigate or traverse upward. (`KEYCODE_DPAD_UP`) + ArrowUp, + /// The End key, used with keyboard entry to go to the end of content (`KEYCODE_MOVE_END`). + End, + /// The Home key, used with keyboard entry, to go to start of content (`KEYCODE_MOVE_HOME`). + /// For the mobile phone `Home` key (which goes to the phone’s main screen), use [`GoHome`]. + /// + /// [`GoHome`]: Self::GoHome + Home, + /// Scroll down or display next page of content. + PageDown, + /// Scroll up or display previous page of content. + PageUp, + /// Used to remove the character to the left of the cursor. This key value is also used for + /// the key labeled `Delete` on MacOS keyboards. + Backspace, + /// Remove the currently selected input. + Clear, + /// Copy the current selection. (`APPCOMMAND_COPY`) + Copy, + /// The Cursor Select key. + CrSel, + /// Cut the current selection. (`APPCOMMAND_CUT`) + Cut, + /// Used to delete the character to the right of the cursor. This key value is also used for the + /// key labeled `Delete` on MacOS keyboards when `Fn` is active. + Delete, + /// The Erase to End of Field key. This key deletes all characters from the current cursor + /// position to the end of the current field. + EraseEof, + /// The Extend Selection (Exsel) key. + ExSel, + /// Toggle between text modes for insertion or overtyping. + /// (`KEYCODE_INSERT`) + Insert, + /// The Paste key. (`APPCOMMAND_PASTE`) + Paste, + /// Redo the last action. (`APPCOMMAND_REDO`) + Redo, + /// Undo the last action. (`APPCOMMAND_UNDO`) + Undo, + /// The Accept (Commit, OK) key. Accept current option or input method sequence conversion. + Accept, + /// Redo or repeat an action. + Again, + /// The Attention (Attn) key. + Attn, + /// The Cancel key. (on linux and web) + Cancel, + /// Show the application’s context menu. + /// This key is commonly found between the right `Super` key and the right `Control` key. + ContextMenu, + /// The `Esc` key. This key was originally used to initiate an escape sequence, but is + /// now more generally used to exit or "escape" the current context, such as closing a dialog + /// or exiting full screen mode. + Escape, + /// The Execute key. + Execute, + /// Open the Find dialog. (`APPCOMMAND_FIND`) + Find, + /// Open a help dialog or toggle display of help information. (`APPCOMMAND_HELP`, + /// `KEYCODE_HELP`) + Help, + /// Pause the current state or application (as appropriate). + /// + /// Note: Do not use this value for the `Pause` button on media controllers. Use `"MediaPause"` + /// instead. + Pause, + /// Play or resume the current state or application (as appropriate). + /// + /// Note: Do not use this value for the `Play` button on media controllers. Use `"MediaPlay"` + /// instead. + Play, + /// The properties (Props) key. + Props, + /// The Select key. + Select, + /// The ZoomIn key. (`KEYCODE_ZOOM_IN`) + ZoomIn, + /// The ZoomOut key. (`KEYCODE_ZOOM_OUT`) + ZoomOut, + /// The Brightness Down key. Typically controls the display brightness. + /// (`KEYCODE_BRIGHTNESS_DOWN`) + BrightnessDown, + /// The Brightness Up key. Typically controls the display brightness. (`KEYCODE_BRIGHTNESS_UP`) + BrightnessUp, + /// Toggle removable media to eject (open) and insert (close) state. (`KEYCODE_MEDIA_EJECT`) + Eject, + /// LogOff + LogOff, + /// Toggle power state. (`KEYCODE_POWER`) + /// Note: Some devices might not expose this key to the operating environment. + Power, + /// The `PowerOff` key. Sometime called `PowerDown`. + PowerOff, + /// Initiate print-screen function. + PrintScreen, + /// The Hibernate key. This key saves the current state of the computer to disk so that it can + /// be restored. The computer will then shutdown. + Hibernate, + /// The Standby key. This key turns off the display and places the computer into a low-power + /// mode without completely shutting down. It is sometimes labelled `Suspend` or `Sleep` key. + /// (`KEYCODE_SLEEP`) + Standby, + /// The WakeUp key. (`KEYCODE_WAKEUP`) + WakeUp, + /// Initate the multi-candidate mode. + AllCandidates, + /// The Alphanumeric key (on linux/web) + Alphanumeric, + /// Initiate the Code Input mode to allow characters to be entered by + /// their code points. + CodeInput, + /// The Compose key, also known as "Multi_key" on the X Window System. This key acts in a + /// manner similar to a dead key, triggering a mode where subsequent key presses are combined to + /// produce a different character. + Compose, + /// Convert the current input method sequence. + Convert, + /// The Final Mode `Final` key used on some Asian keyboards, to enable the final mode for IMEs. + FinalMode, + /// Switch to the first character group. (ISO/IEC 9995) + GroupFirst, + /// Switch to the last character group. (ISO/IEC 9995) + GroupLast, + /// Switch to the next character group. (ISO/IEC 9995) + GroupNext, + /// Switch to the previous character group. (ISO/IEC 9995) + GroupPrevious, + /// Toggle between or cycle through input modes of IMEs. + ModeChange, + /// NextCandidate, web only. + NextCandidate, + /// Accept current input method sequence without + /// conversion in IMEs. + NonConvert, + /// PreviousCandidate, web only. + PreviousCandidate, + /// IME PROCESS key + Process, + /// SingleCandidate + SingleCandidate, + /// Toggle between Hangul and English modes. + HangulMode, + /// HanjaMode + HanjaMode, + /// JunjaMode + JunjaMode, + /// The Eisu key. This key may close the IME, but its purpose is defined by the current IME. + /// (`KEYCODE_EISU`) + Eisu, + /// The (Half-Width) Characters key. + Hankaku, + /// The Hiragana (Japanese Kana characters) key. + Hiragana, + /// The Hiragana/Katakana toggle key. (`KEYCODE_KATAKANA_HIRAGANA`) + HiraganaKatakana, + /// The Kana Mode (Kana Lock) key. This key is used to enter hiragana mode (typically from + /// romaji mode). + KanaMode, + /// The Kanji (Japanese name for ideographic characters of Chinese origin) Mode key. This key is + /// typically used to switch to a hiragana keyboard for the purpose of converting input into + /// kanji. (`KEYCODE_KANA`) + KanjiMode, + /// The Katakana (Japanese Kana characters) key. + Katakana, + /// The Roman characters function key. + Romaji, + /// The Zenkaku (Full-Width) Characters key. + Zenkaku, + /// The Zenkaku/Hankaku (full-width/half-width) toggle key. (`KEYCODE_ZENKAKU_HANKAKU`) + ZenkakuHankaku, + /// General purpose virtual function key, as index 1. + Soft1, + /// General purpose virtual function key, as index 2. + Soft2, + /// General purpose virtual function key, as index 3. + Soft3, + /// General purpose virtual function key, as index 4. + Soft4, + /// Select next (numerically or logically) lower channel. (`APPCOMMAND_MEDIA_CHANNEL_DOWN`, + /// `KEYCODE_CHANNEL_DOWN`) + ChannelDown, + /// Select next (numerically or logically) higher channel. (`APPCOMMAND_MEDIA_CHANNEL_UP`, + /// `KEYCODE_CHANNEL_UP`) + ChannelUp, + /// Close the current document or message (Note: This doesn’t close the application). + /// (`APPCOMMAND_CLOSE`) + Close, + /// Open an editor to forward the current message. (`APPCOMMAND_FORWARD_MAIL`) + MailForward, + /// Open an editor to reply to the current message. (`APPCOMMAND_REPLY_TO_MAIL`) + MailReply, + /// Send the current message. (`APPCOMMAND_SEND_MAIL`) + MailSend, + /// Close the current media, for example to close a CD or DVD tray. (`KEYCODE_MEDIA_CLOSE`) + MediaClose, + /// Initiate or continue forward playback at faster than normal speed, or increase speed if + /// already fast forwarding. (`APPCOMMAND_MEDIA_FAST_FORWARD`, `KEYCODE_MEDIA_FAST_FORWARD`) + MediaFastForward, + /// Pause the currently playing media. (`APPCOMMAND_MEDIA_PAUSE`, `KEYCODE_MEDIA_PAUSE`) + /// + /// Note: Media controller devices should use this value rather than `"Pause"` for their pause + /// keys. + MediaPause, + /// Initiate or continue media playback at normal speed, if not currently playing at normal + /// speed. (`APPCOMMAND_MEDIA_PLAY`, `KEYCODE_MEDIA_PLAY`) + MediaPlay, + /// Toggle media between play and pause states. (`APPCOMMAND_MEDIA_PLAY_PAUSE`, + /// `KEYCODE_MEDIA_PLAY_PAUSE`) + MediaPlayPause, + /// Initiate or resume recording of currently selected media. (`APPCOMMAND_MEDIA_RECORD`, + /// `KEYCODE_MEDIA_RECORD`) + MediaRecord, + /// Initiate or continue reverse playback at faster than normal speed, or increase speed if + /// already rewinding. (`APPCOMMAND_MEDIA_REWIND`, `KEYCODE_MEDIA_REWIND`) + MediaRewind, + /// Stop media playing, pausing, forwarding, rewinding, or recording, if not already stopped. + /// (`APPCOMMAND_MEDIA_STOP`, `KEYCODE_MEDIA_STOP`) + MediaStop, + /// Seek to next media or program track. (`APPCOMMAND_MEDIA_NEXTTRACK`, `KEYCODE_MEDIA_NEXT`) + MediaTrackNext, + /// Seek to previous media or program track. (`APPCOMMAND_MEDIA_PREVIOUSTRACK`, + /// `KEYCODE_MEDIA_PREVIOUS`) + MediaTrackPrevious, + /// Open a new document or message. (`APPCOMMAND_NEW`) + New, + /// Open an existing document or message. (`APPCOMMAND_OPEN`) + Open, + /// Print the current document or message. (`APPCOMMAND_PRINT`) + Print, + /// Save the current document or message. (`APPCOMMAND_SAVE`) + Save, + /// Spellcheck the current document or selection. (`APPCOMMAND_SPELL_CHECK`) + SpellCheck, + /// The `11` key found on media numpads that + /// have buttons from `1` ... `12`. + Key11, + /// The `12` key found on media numpads that + /// have buttons from `1` ... `12`. + Key12, + /// Adjust audio balance leftward. (`VK_AUDIO_BALANCE_LEFT`) + AudioBalanceLeft, + /// Adjust audio balance rightward. (`VK_AUDIO_BALANCE_RIGHT`) + AudioBalanceRight, + /// Decrease audio bass boost or cycle down through bass boost states. (`APPCOMMAND_BASS_DOWN`, + /// `VK_BASS_BOOST_DOWN`) + AudioBassBoostDown, + /// Toggle bass boost on/off. (`APPCOMMAND_BASS_BOOST`) + AudioBassBoostToggle, + /// Increase audio bass boost or cycle up through bass boost states. (`APPCOMMAND_BASS_UP`, + /// `VK_BASS_BOOST_UP`) + AudioBassBoostUp, + /// Adjust audio fader towards front. (`VK_FADER_FRONT`) + AudioFaderFront, + /// Adjust audio fader towards rear. (`VK_FADER_REAR`) + AudioFaderRear, + /// Advance surround audio mode to next available mode. (`VK_SURROUND_MODE_NEXT`) + AudioSurroundModeNext, + /// Decrease treble. (`APPCOMMAND_TREBLE_DOWN`) + AudioTrebleDown, + /// Increase treble. (`APPCOMMAND_TREBLE_UP`) + AudioTrebleUp, + /// Decrease audio volume. (`APPCOMMAND_VOLUME_DOWN`, `KEYCODE_VOLUME_DOWN`) + AudioVolumeDown, + /// Increase audio volume. (`APPCOMMAND_VOLUME_UP`, `KEYCODE_VOLUME_UP`) + AudioVolumeUp, + /// Toggle between muted state and prior volume level. (`APPCOMMAND_VOLUME_MUTE`, + /// `KEYCODE_VOLUME_MUTE`) + AudioVolumeMute, + /// Toggle the microphone on/off. (`APPCOMMAND_MIC_ON_OFF_TOGGLE`) + MicrophoneToggle, + /// Decrease microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_DOWN`) + MicrophoneVolumeDown, + /// Increase microphone volume. (`APPCOMMAND_MICROPHONE_VOLUME_UP`) + MicrophoneVolumeUp, + /// Mute the microphone. (`APPCOMMAND_MICROPHONE_VOLUME_MUTE`, `KEYCODE_MUTE`) + MicrophoneVolumeMute, + /// Show correction list when a word is incorrectly identified. (`APPCOMMAND_CORRECTION_LIST`) + SpeechCorrectionList, + /// Toggle between dictation mode and command/control mode. + /// (`APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE`) + SpeechInputToggle, + /// The first generic "LaunchApplication" key. This is commonly associated with launching "My + /// Computer", and may have a computer symbol on the key. (`APPCOMMAND_LAUNCH_APP1`) + LaunchApplication1, + /// The second generic "LaunchApplication" key. This is commonly associated with launching + /// "Calculator", and may have a calculator symbol on the key. (`APPCOMMAND_LAUNCH_APP2`, + /// `KEYCODE_CALCULATOR`) + LaunchApplication2, + /// The "Calendar" key. (`KEYCODE_CALENDAR`) + LaunchCalendar, + /// The "Contacts" key. (`KEYCODE_CONTACTS`) + LaunchContacts, + /// The "Mail" key. (`APPCOMMAND_LAUNCH_MAIL`) + LaunchMail, + /// The "Media Player" key. (`APPCOMMAND_LAUNCH_MEDIA_SELECT`) + LaunchMediaPlayer, + /// LaunchMusicPlayer + LaunchMusicPlayer, + /// LaunchPhone + LaunchPhone, + /// LaunchScreenSaver + LaunchScreenSaver, + /// LaunchSpreadsheet + LaunchSpreadsheet, + /// LaunchWebBrowser + LaunchWebBrowser, + /// LaunchWebCam + LaunchWebCam, + /// LaunchWordProcessor + LaunchWordProcessor, + /// Navigate to previous content or page in current history. (`APPCOMMAND_BROWSER_BACKWARD`) + BrowserBack, + /// Open the list of browser favorites. (`APPCOMMAND_BROWSER_FAVORITES`) + BrowserFavorites, + /// Navigate to next content or page in current history. (`APPCOMMAND_BROWSER_FORWARD`) + BrowserForward, + /// Go to the user’s preferred home page. (`APPCOMMAND_BROWSER_HOME`) + BrowserHome, + /// Refresh the current page or content. (`APPCOMMAND_BROWSER_REFRESH`) + BrowserRefresh, + /// Call up the user’s preferred search page. (`APPCOMMAND_BROWSER_SEARCH`) + BrowserSearch, + /// Stop loading the current page or content. (`APPCOMMAND_BROWSER_STOP`) + BrowserStop, + /// The Application switch key, which provides a list of recent apps to switch between. + /// (`KEYCODE_APP_SWITCH`) + AppSwitch, + /// The Call key. (`KEYCODE_CALL`) + Call, + /// The Camera key. (`KEYCODE_CAMERA`) + Camera, + /// The Camera focus key. (`KEYCODE_FOCUS`) + CameraFocus, + /// The End Call key. (`KEYCODE_ENDCALL`) + EndCall, + /// The Back key. (`KEYCODE_BACK`) + GoBack, + /// The Home key, which goes to the phone’s main screen. (`KEYCODE_HOME`) + GoHome, + /// The Headset Hook key. (`KEYCODE_HEADSETHOOK`) + HeadsetHook, + /// LastNumberRedial + LastNumberRedial, + /// The Notification key. (`KEYCODE_NOTIFICATION`) + Notification, + /// Toggle between manner mode state: silent, vibrate, ring, ... (`KEYCODE_MANNER_MODE`) + MannerMode, + /// VoiceDial + VoiceDial, + /// Switch to viewing TV. (`KEYCODE_TV`) + TV, + /// TV 3D Mode. (`KEYCODE_3D_MODE`) + TV3DMode, + /// Toggle between antenna and cable input. (`KEYCODE_TV_ANTENNA_CABLE`) + TVAntennaCable, + /// Audio description. (`KEYCODE_TV_AUDIO_DESCRIPTION`) + TVAudioDescription, + /// Audio description mixing volume down. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN`) + TVAudioDescriptionMixDown, + /// Audio description mixing volume up. (`KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP`) + TVAudioDescriptionMixUp, + /// Contents menu. (`KEYCODE_TV_CONTENTS_MENU`) + TVContentsMenu, + /// Contents menu. (`KEYCODE_TV_DATA_SERVICE`) + TVDataService, + /// Switch the input mode on an external TV. (`KEYCODE_TV_INPUT`) + TVInput, + /// Switch to component input #1. (`KEYCODE_TV_INPUT_COMPONENT_1`) + TVInputComponent1, + /// Switch to component input #2. (`KEYCODE_TV_INPUT_COMPONENT_2`) + TVInputComponent2, + /// Switch to composite input #1. (`KEYCODE_TV_INPUT_COMPOSITE_1`) + TVInputComposite1, + /// Switch to composite input #2. (`KEYCODE_TV_INPUT_COMPOSITE_2`) + TVInputComposite2, + /// Switch to HDMI input #1. (`KEYCODE_TV_INPUT_HDMI_1`) + TVInputHDMI1, + /// Switch to HDMI input #2. (`KEYCODE_TV_INPUT_HDMI_2`) + TVInputHDMI2, + /// Switch to HDMI input #3. (`KEYCODE_TV_INPUT_HDMI_3`) + TVInputHDMI3, + /// Switch to HDMI input #4. (`KEYCODE_TV_INPUT_HDMI_4`) + TVInputHDMI4, + /// Switch to VGA input #1. (`KEYCODE_TV_INPUT_VGA_1`) + TVInputVGA1, + /// Media context menu. (`KEYCODE_TV_MEDIA_CONTEXT_MENU`) + TVMediaContext, + /// Toggle network. (`KEYCODE_TV_NETWORK`) + TVNetwork, + /// Number entry. (`KEYCODE_TV_NUMBER_ENTRY`) + TVNumberEntry, + /// Toggle the power on an external TV. (`KEYCODE_TV_POWER`) + TVPower, + /// Radio. (`KEYCODE_TV_RADIO_SERVICE`) + TVRadioService, + /// Satellite. (`KEYCODE_TV_SATELLITE`) + TVSatellite, + /// Broadcast Satellite. (`KEYCODE_TV_SATELLITE_BS`) + TVSatelliteBS, + /// Communication Satellite. (`KEYCODE_TV_SATELLITE_CS`) + TVSatelliteCS, + /// Toggle between available satellites. (`KEYCODE_TV_SATELLITE_SERVICE`) + TVSatelliteToggle, + /// Analog Terrestrial. (`KEYCODE_TV_TERRESTRIAL_ANALOG`) + TVTerrestrialAnalog, + /// Digital Terrestrial. (`KEYCODE_TV_TERRESTRIAL_DIGITAL`) + TVTerrestrialDigital, + /// Timer programming. (`KEYCODE_TV_TIMER_PROGRAMMING`) + TVTimer, + /// Switch the input mode on an external AVR (audio/video receiver). (`KEYCODE_AVR_INPUT`) + AVRInput, + /// Toggle the power on an external AVR (audio/video receiver). (`KEYCODE_AVR_POWER`) + AVRPower, + /// General purpose color-coded media function key, as index 0 (red). (`VK_COLORED_KEY_0`, + /// `KEYCODE_PROG_RED`) + ColorF0Red, + /// General purpose color-coded media function key, as index 1 (green). (`VK_COLORED_KEY_1`, + /// `KEYCODE_PROG_GREEN`) + ColorF1Green, + /// General purpose color-coded media function key, as index 2 (yellow). (`VK_COLORED_KEY_2`, + /// `KEYCODE_PROG_YELLOW`) + ColorF2Yellow, + /// General purpose color-coded media function key, as index 3 (blue). (`VK_COLORED_KEY_3`, + /// `KEYCODE_PROG_BLUE`) + ColorF3Blue, + /// General purpose color-coded media function key, as index 4 (grey). (`VK_COLORED_KEY_4`) + ColorF4Grey, + /// General purpose color-coded media function key, as index 5 (brown). (`VK_COLORED_KEY_5`) + ColorF5Brown, + /// Toggle the display of Closed Captions. (`VK_CC`, `KEYCODE_CAPTIONS`) + ClosedCaptionToggle, + /// Adjust brightness of device, by toggling between or cycling through states. (`VK_DIMMER`) + Dimmer, + /// Swap video sources. (`VK_DISPLAY_SWAP`) + DisplaySwap, + /// Select Digital Video Recorder. (`KEYCODE_DVR`) + DVR, + /// Exit the current application. (`VK_EXIT`) + Exit, + /// Clear program or content stored as favorite 0. (`VK_CLEAR_FAVORITE_0`) + FavoriteClear0, + /// Clear program or content stored as favorite 1. (`VK_CLEAR_FAVORITE_1`) + FavoriteClear1, + /// Clear program or content stored as favorite 2. (`VK_CLEAR_FAVORITE_2`) + FavoriteClear2, + /// Clear program or content stored as favorite 3. (`VK_CLEAR_FAVORITE_3`) + FavoriteClear3, + /// Select (recall) program or content stored as favorite 0. (`VK_RECALL_FAVORITE_0`) + FavoriteRecall0, + /// Select (recall) program or content stored as favorite 1. (`VK_RECALL_FAVORITE_1`) + FavoriteRecall1, + /// Select (recall) program or content stored as favorite 2. (`VK_RECALL_FAVORITE_2`) + FavoriteRecall2, + /// Select (recall) program or content stored as favorite 3. (`VK_RECALL_FAVORITE_3`) + FavoriteRecall3, + /// Store current program or content as favorite 0. (`VK_STORE_FAVORITE_0`) + FavoriteStore0, + /// Store current program or content as favorite 1. (`VK_STORE_FAVORITE_1`) + FavoriteStore1, + /// Store current program or content as favorite 2. (`VK_STORE_FAVORITE_2`) + FavoriteStore2, + /// Store current program or content as favorite 3. (`VK_STORE_FAVORITE_3`) + FavoriteStore3, + /// Toggle display of program or content guide. (`VK_GUIDE`, `KEYCODE_GUIDE`) + Guide, + /// If guide is active and displayed, then display next day’s content. (`VK_NEXT_DAY`) + GuideNextDay, + /// If guide is active and displayed, then display previous day’s content. (`VK_PREV_DAY`) + GuidePreviousDay, + /// Toggle display of information about currently selected context or media. (`VK_INFO`, + /// `KEYCODE_INFO`) + Info, + /// Toggle instant replay. (`VK_INSTANT_REPLAY`) + InstantReplay, + /// Launch linked content, if available and appropriate. (`VK_LINK`) + Link, + /// List the current program. (`VK_LIST`) + ListProgram, + /// Toggle display listing of currently available live content or programs. (`VK_LIVE`) + LiveContent, + /// Lock or unlock current content or program. (`VK_LOCK`) + Lock, + /// Show a list of media applications: audio/video players and image viewers. (`VK_APPS`) + /// + /// Note: Do not confuse this key value with the Windows' `VK_APPS` / `VK_CONTEXT_MENU` key, + /// which is encoded as `"ContextMenu"`. + MediaApps, + /// Audio track key. (`KEYCODE_MEDIA_AUDIO_TRACK`) + MediaAudioTrack, + /// Select previously selected channel or media. (`VK_LAST`, `KEYCODE_LAST_CHANNEL`) + MediaLast, + /// Skip backward to next content or program. (`KEYCODE_MEDIA_SKIP_BACKWARD`) + MediaSkipBackward, + /// Skip forward to next content or program. (`VK_SKIP`, `KEYCODE_MEDIA_SKIP_FORWARD`) + MediaSkipForward, + /// Step backward to next content or program. (`KEYCODE_MEDIA_STEP_BACKWARD`) + MediaStepBackward, + /// Step forward to next content or program. (`KEYCODE_MEDIA_STEP_FORWARD`) + MediaStepForward, + /// Media top menu. (`KEYCODE_MEDIA_TOP_MENU`) + MediaTopMenu, + /// Navigate in. (`KEYCODE_NAVIGATE_IN`) + NavigateIn, + /// Navigate to next key. (`KEYCODE_NAVIGATE_NEXT`) + NavigateNext, + /// Navigate out. (`KEYCODE_NAVIGATE_OUT`) + NavigateOut, + /// Navigate to previous key. (`KEYCODE_NAVIGATE_PREVIOUS`) + NavigatePrevious, + /// Cycle to next favorite channel (in favorites list). (`VK_NEXT_FAVORITE_CHANNEL`) + NextFavoriteChannel, + /// Cycle to next user profile (if there are multiple user profiles). (`VK_USER`) + NextUserProfile, + /// Access on-demand content or programs. (`VK_ON_DEMAND`) + OnDemand, + /// Pairing key to pair devices. (`KEYCODE_PAIRING`) + Pairing, + /// Move picture-in-picture window down. (`VK_PINP_DOWN`) + PinPDown, + /// Move picture-in-picture window. (`VK_PINP_MOVE`) + PinPMove, + /// Toggle display of picture-in-picture window. (`VK_PINP_TOGGLE`) + PinPToggle, + /// Move picture-in-picture window up. (`VK_PINP_UP`) + PinPUp, + /// Decrease media playback speed. (`VK_PLAY_SPEED_DOWN`) + PlaySpeedDown, + /// Reset playback to normal speed. (`VK_PLAY_SPEED_RESET`) + PlaySpeedReset, + /// Increase media playback speed. (`VK_PLAY_SPEED_UP`) + PlaySpeedUp, + /// Toggle random media or content shuffle mode. (`VK_RANDOM_TOGGLE`) + RandomToggle, + /// Not a physical key, but this key code is sent when the remote control battery is low. + /// (`VK_RC_LOW_BATTERY`) + RcLowBattery, + /// Toggle or cycle between media recording speeds. (`VK_RECORD_SPEED_NEXT`) + RecordSpeedNext, + /// Toggle RF (radio frequency) input bypass mode (pass RF input directly to the RF output). + /// (`VK_RF_BYPASS`) + RfBypass, + /// Toggle scan channels mode. (`VK_SCAN_CHANNELS_TOGGLE`) + ScanChannelsToggle, + /// Advance display screen mode to next available mode. (`VK_SCREEN_MODE_NEXT`) + ScreenModeNext, + /// Toggle display of device settings screen. (`VK_SETTINGS`, `KEYCODE_SETTINGS`) + Settings, + /// Toggle split screen mode. (`VK_SPLIT_SCREEN_TOGGLE`) + SplitScreenToggle, + /// Switch the input mode on an external STB (set top box). (`KEYCODE_STB_INPUT`) + STBInput, + /// Toggle the power on an external STB (set top box). (`KEYCODE_STB_POWER`) + STBPower, + /// Toggle display of subtitles, if available. (`VK_SUBTITLE`) + Subtitle, + /// Toggle display of teletext, if available (`VK_TELETEXT`, `KEYCODE_TV_TELETEXT`). + Teletext, + /// Advance video mode to next available mode. (`VK_VIDEO_MODE_NEXT`) + VideoModeNext, + /// Cause device to identify itself in some manner, e.g., audibly or visibly. (`VK_WINK`) + Wink, + /// Toggle between full-screen and scaled content, or alter magnification level. (`VK_ZOOM`, + /// `KEYCODE_TV_ZOOM_MODE`) + ZoomToggle, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F1, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F2, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F3, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F4, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F5, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F6, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F7, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F8, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F9, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F10, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F11, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F12, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F13, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F14, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F15, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F16, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F17, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F18, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F19, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F20, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F21, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F22, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F23, + /// General-purpose function key. + /// Usually found at the top of the keyboard. + F24, + /// General-purpose function key. + F25, + /// General-purpose function key. + F26, + /// General-purpose function key. + F27, + /// General-purpose function key. + F28, + /// General-purpose function key. + F29, + /// General-purpose function key. + F30, + /// General-purpose function key. + F31, + /// General-purpose function key. + F32, + /// General-purpose function key. + F33, + /// General-purpose function key. + F34, + /// General-purpose function key. + F35, +} diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index c3f2b3af9e4f2..d08ed93ce890e 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -36,7 +36,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; -use keyboard::{keyboard_input_system, KeyCode, KeyboardInput}; +use keyboard::{keyboard_input_system, Key, KeyCode, KeyboardInput, NativeKey, NativeKeyCode}; use mouse::{ mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel, @@ -114,7 +114,10 @@ impl Plugin for InputPlugin { // Register keyboard types app.register_type::() - .register_type::(); + .register_type::() + .register_type::() + .register_type::() + .register_type::(); // Register mouse types app.register_type::() diff --git a/crates/bevy_math/src/bounding/bounded2d/mod.rs b/crates/bevy_math/src/bounding/bounded2d/mod.rs index 252c507192c62..e8c44094a9f95 100644 --- a/crates/bevy_math/src/bounding/bounded2d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded2d/mod.rs @@ -2,7 +2,7 @@ mod primitive_impls; use glam::Mat2; -use super::BoundingVolume; +use super::{BoundingVolume, IntersectsVolume}; use crate::prelude::Vec2; /// Computes the geometric center of the given set of points. @@ -80,6 +80,16 @@ impl Aabb2d { let radius = self.min.distance(self.max) / 2.0; BoundingCircle::new(self.center(), radius) } + + /// Finds the point on the AABB that is closest to the given `point`. + /// + /// If the point is outside the AABB, the returned point will be on the perimeter of the AABB. + /// Otherwise, it will be inside the AABB and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec2) -> Vec2 { + // Clamp point coordinates to the AABB + point.clamp(self.min, self.max) + } } impl BoundingVolume for Aabb2d { @@ -139,10 +149,32 @@ impl BoundingVolume for Aabb2d { } } +impl IntersectsVolume for Aabb2d { + #[inline(always)] + fn intersects(&self, other: &Self) -> bool { + let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x; + let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y; + x_overlaps && y_overlaps + } +} + +impl IntersectsVolume for Aabb2d { + #[inline(always)] + fn intersects(&self, circle: &BoundingCircle) -> bool { + let closest_point = self.closest_point(circle.center); + let distance_squared = circle.center.distance_squared(closest_point); + let radius_squared = circle.radius().powi(2); + distance_squared <= radius_squared + } +} + #[cfg(test)] mod aabb2d_tests { use super::Aabb2d; - use crate::{bounding::BoundingVolume, Vec2}; + use crate::{ + bounding::{BoundingCircle, BoundingVolume, IntersectsVolume}, + Vec2, + }; #[test] fn center() { @@ -244,6 +276,53 @@ mod aabb2d_tests { assert!(a.contains(&shrunk)); assert!(!shrunk.contains(&a)); } + + #[test] + fn closest_point() { + let aabb = Aabb2d { + min: Vec2::NEG_ONE, + max: Vec2::ONE, + }; + assert_eq!(aabb.closest_point(Vec2::X * 10.0), Vec2::X); + assert_eq!(aabb.closest_point(Vec2::NEG_ONE * 10.0), Vec2::NEG_ONE); + assert_eq!( + aabb.closest_point(Vec2::new(0.25, 0.1)), + Vec2::new(0.25, 0.1) + ); + } + + #[test] + fn intersect_aabb() { + let aabb = Aabb2d { + min: Vec2::NEG_ONE, + max: Vec2::ONE, + }; + assert!(aabb.intersects(&aabb)); + assert!(aabb.intersects(&Aabb2d { + min: Vec2::new(0.5, 0.5), + max: Vec2::new(2.0, 2.0), + })); + assert!(aabb.intersects(&Aabb2d { + min: Vec2::new(-2.0, -2.0), + max: Vec2::new(-0.5, -0.5), + })); + assert!(!aabb.intersects(&Aabb2d { + min: Vec2::new(1.1, 0.0), + max: Vec2::new(2.0, 0.5), + })); + } + + #[test] + fn intersect_bounding_circle() { + let aabb = Aabb2d { + min: Vec2::NEG_ONE, + max: Vec2::ONE, + }; + assert!(aabb.intersects(&BoundingCircle::new(Vec2::ZERO, 1.0))); + assert!(aabb.intersects(&BoundingCircle::new(Vec2::ONE * 1.5, 1.0))); + assert!(aabb.intersects(&BoundingCircle::new(Vec2::NEG_ONE * 1.5, 1.0))); + assert!(!aabb.intersects(&BoundingCircle::new(Vec2::ONE * 1.75, 1.0))); + } } use crate::primitives::Circle; @@ -305,6 +384,15 @@ impl BoundingCircle { max: self.center + Vec2::splat(self.radius()), } } + + /// Finds the point on the bounding circle that is closest to the given `point`. + /// + /// If the point is outside the circle, the returned point will be on the perimeter of the circle. + /// Otherwise, it will be inside the circle and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec2) -> Vec2 { + self.circle.closest_point(point - self.center) + self.center + } } impl BoundingVolume for BoundingCircle { @@ -363,10 +451,29 @@ impl BoundingVolume for BoundingCircle { } } +impl IntersectsVolume for BoundingCircle { + #[inline(always)] + fn intersects(&self, other: &Self) -> bool { + let center_distance_squared = self.center.distance_squared(other.center); + let radius_sum_squared = (self.radius() + other.radius()).powi(2); + center_distance_squared <= radius_sum_squared + } +} + +impl IntersectsVolume for BoundingCircle { + #[inline(always)] + fn intersects(&self, aabb: &Aabb2d) -> bool { + aabb.intersects(self) + } +} + #[cfg(test)] mod bounding_circle_tests { use super::BoundingCircle; - use crate::{bounding::BoundingVolume, Vec2}; + use crate::{ + bounding::{BoundingVolume, IntersectsVolume}, + Vec2, + }; #[test] fn area() { @@ -443,4 +550,27 @@ mod bounding_circle_tests { assert!(a.contains(&shrunk)); assert!(!shrunk.contains(&a)); } + + #[test] + fn closest_point() { + let circle = BoundingCircle::new(Vec2::ZERO, 1.0); + assert_eq!(circle.closest_point(Vec2::X * 10.0), Vec2::X); + assert_eq!( + circle.closest_point(Vec2::NEG_ONE * 10.0), + Vec2::NEG_ONE.normalize() + ); + assert_eq!( + circle.closest_point(Vec2::new(0.25, 0.1)), + Vec2::new(0.25, 0.1) + ); + } + + #[test] + fn intersect_bounding_circle() { + let circle = BoundingCircle::new(Vec2::ZERO, 1.0); + assert!(circle.intersects(&BoundingCircle::new(Vec2::ZERO, 1.0))); + assert!(circle.intersects(&BoundingCircle::new(Vec2::ONE * 1.25, 1.0))); + assert!(circle.intersects(&BoundingCircle::new(Vec2::NEG_ONE * 1.25, 1.0))); + assert!(!circle.intersects(&BoundingCircle::new(Vec2::ONE * 1.5, 1.0))); + } } diff --git a/crates/bevy_math/src/bounding/bounded3d/mod.rs b/crates/bevy_math/src/bounding/bounded3d/mod.rs index 65c843a79f3dd..bc2f9390a4b8a 100644 --- a/crates/bevy_math/src/bounding/bounded3d/mod.rs +++ b/crates/bevy_math/src/bounding/bounded3d/mod.rs @@ -1,6 +1,6 @@ mod primitive_impls; -use super::BoundingVolume; +use super::{BoundingVolume, IntersectsVolume}; use crate::prelude::{Quat, Vec3}; /// Computes the geometric center of the given set of points. @@ -74,6 +74,16 @@ impl Aabb3d { let radius = self.min.distance(self.max) / 2.0; BoundingSphere::new(self.center(), radius) } + + /// Finds the point on the AABB that is closest to the given `point`. + /// + /// If the point is outside the AABB, the returned point will be on the surface of the AABB. + /// Otherwise, it will be inside the AABB and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec3) -> Vec3 { + // Clamp point coordinates to the AABB + point.clamp(self.min, self.max) + } } impl BoundingVolume for Aabb3d { @@ -135,10 +145,33 @@ impl BoundingVolume for Aabb3d { } } +impl IntersectsVolume for Aabb3d { + #[inline(always)] + fn intersects(&self, other: &Self) -> bool { + let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x; + let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y; + let z_overlaps = self.min.z <= other.max.z && self.max.z >= other.min.z; + x_overlaps && y_overlaps && z_overlaps + } +} + +impl IntersectsVolume for Aabb3d { + #[inline(always)] + fn intersects(&self, sphere: &BoundingSphere) -> bool { + let closest_point = self.closest_point(sphere.center); + let distance_squared = sphere.center.distance_squared(closest_point); + let radius_squared = sphere.radius().powi(2); + distance_squared <= radius_squared + } +} + #[cfg(test)] mod aabb3d_tests { use super::Aabb3d; - use crate::{bounding::BoundingVolume, Vec3}; + use crate::{ + bounding::{BoundingSphere, BoundingVolume, IntersectsVolume}, + Vec3, + }; #[test] fn center() { @@ -239,6 +272,53 @@ mod aabb3d_tests { assert!(a.contains(&shrunk)); assert!(!shrunk.contains(&a)); } + + #[test] + fn closest_point() { + let aabb = Aabb3d { + min: Vec3::NEG_ONE, + max: Vec3::ONE, + }; + assert_eq!(aabb.closest_point(Vec3::X * 10.0), Vec3::X); + assert_eq!(aabb.closest_point(Vec3::NEG_ONE * 10.0), Vec3::NEG_ONE); + assert_eq!( + aabb.closest_point(Vec3::new(0.25, 0.1, 0.3)), + Vec3::new(0.25, 0.1, 0.3) + ); + } + + #[test] + fn intersect_aabb() { + let aabb = Aabb3d { + min: Vec3::NEG_ONE, + max: Vec3::ONE, + }; + assert!(aabb.intersects(&aabb)); + assert!(aabb.intersects(&Aabb3d { + min: Vec3::splat(0.5), + max: Vec3::splat(2.0), + })); + assert!(aabb.intersects(&Aabb3d { + min: Vec3::splat(-2.0), + max: Vec3::splat(-0.5), + })); + assert!(!aabb.intersects(&Aabb3d { + min: Vec3::new(1.1, 0.0, 0.0), + max: Vec3::new(2.0, 0.5, 0.25), + })); + } + + #[test] + fn intersect_bounding_sphere() { + let aabb = Aabb3d { + min: Vec3::NEG_ONE, + max: Vec3::ONE, + }; + assert!(aabb.intersects(&BoundingSphere::new(Vec3::ZERO, 1.0))); + assert!(aabb.intersects(&BoundingSphere::new(Vec3::ONE * 1.5, 1.0))); + assert!(aabb.intersects(&BoundingSphere::new(Vec3::NEG_ONE * 1.5, 1.0))); + assert!(!aabb.intersects(&BoundingSphere::new(Vec3::ONE * 1.75, 1.0))); + } } use crate::primitives::Sphere; @@ -296,6 +376,15 @@ impl BoundingSphere { max: self.center + Vec3::splat(self.radius()), } } + + /// Finds the point on the bounding sphere that is closest to the given `point`. + /// + /// If the point is outside the sphere, the returned point will be on the surface of the sphere. + /// Otherwise, it will be inside the sphere and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec3) -> Vec3 { + self.sphere.closest_point(point - self.center) + self.center + } } impl BoundingVolume for BoundingSphere { @@ -364,10 +453,29 @@ impl BoundingVolume for BoundingSphere { } } +impl IntersectsVolume for BoundingSphere { + #[inline(always)] + fn intersects(&self, other: &Self) -> bool { + let center_distance_squared = self.center.distance_squared(other.center); + let radius_sum_squared = (self.radius() + other.radius()).powi(2); + center_distance_squared <= radius_sum_squared + } +} + +impl IntersectsVolume for BoundingSphere { + #[inline(always)] + fn intersects(&self, aabb: &Aabb3d) -> bool { + aabb.intersects(self) + } +} + #[cfg(test)] mod bounding_sphere_tests { use super::BoundingSphere; - use crate::{bounding::BoundingVolume, Vec3}; + use crate::{ + bounding::{BoundingVolume, IntersectsVolume}, + Vec3, + }; #[test] fn area() { @@ -444,4 +552,27 @@ mod bounding_sphere_tests { assert!(a.contains(&shrunk)); assert!(!shrunk.contains(&a)); } + + #[test] + fn closest_point() { + let sphere = BoundingSphere::new(Vec3::ZERO, 1.0); + assert_eq!(sphere.closest_point(Vec3::X * 10.0), Vec3::X); + assert_eq!( + sphere.closest_point(Vec3::NEG_ONE * 10.0), + Vec3::NEG_ONE.normalize() + ); + assert_eq!( + sphere.closest_point(Vec3::new(0.25, 0.1, 0.3)), + Vec3::new(0.25, 0.1, 0.3) + ); + } + + #[test] + fn intersect_bounding_sphere() { + let sphere = BoundingSphere::new(Vec3::ZERO, 1.0); + assert!(sphere.intersects(&BoundingSphere::new(Vec3::ZERO, 1.0))); + assert!(sphere.intersects(&BoundingSphere::new(Vec3::ONE * 1.1, 1.0))); + assert!(sphere.intersects(&BoundingSphere::new(Vec3::NEG_ONE * 1.1, 1.0))); + assert!(!sphere.intersects(&BoundingSphere::new(Vec3::ONE * 1.2, 1.0))); + } } diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index 8125aae21873d..b992fb517ea22 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -150,7 +150,8 @@ impl Bounded3d for Capsule { fn aabb_3d(&self, translation: Vec3, rotation: Quat) -> Aabb3d { // Get the line segment between the hemispheres of the rotated capsule let segment = Segment3d { - direction: Direction3d::from_normalized(rotation * Vec3::Y), + // Multiplying a normalized vector (Vec3::Y) with a rotation returns a normalized vector. + direction: Direction3d::new_unchecked(rotation * Vec3::Y), half_length: self.half_length, }; let (a, b) = (segment.point1(), segment.point2()); diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index cb832f9f614a3..63d7c3896aa8b 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -24,6 +24,17 @@ impl Direction2d { Self::new_and_length(value).map(|(dir, _)| dir) } + /// Create a [`Direction2d`] from a [`Vec2`] that is already normalized. + /// + /// # Warning + /// + /// `value` must be normalized, i.e it's length must be `1.0`. + pub fn new_unchecked(value: Vec2) -> Self { + debug_assert!(value.is_normalized()); + + Self(value) + } + /// Create a direction from a finite, nonzero [`Vec2`], also returning its original length. /// /// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length @@ -34,7 +45,7 @@ impl Direction2d { direction .map(|dir| (Self(dir), length)) - .map_or(Err(InvalidDirectionError::from_length(length)), Ok) + .ok_or(InvalidDirectionError::from_length(length)) } /// Create a direction from its `x` and `y` components. @@ -44,12 +55,6 @@ impl Direction2d { pub fn from_xy(x: f32, y: f32) -> Result { Self::new(Vec2::new(x, y)) } - - /// Create a direction from a [`Vec2`] that is already normalized. - pub fn from_normalized(value: Vec2) -> Self { - debug_assert!(value.is_normalized()); - Self(value) - } } impl TryFrom for Direction2d { @@ -82,6 +87,27 @@ pub struct Circle { } impl Primitive2d for Circle {} +impl Circle { + /// Finds the point on the circle that is closest to the given `point`. + /// + /// If the point is outside the circle, the returned point will be on the perimeter of the circle. + /// Otherwise, it will be inside the circle and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec2) -> Vec2 { + let distance_squared = point.length_squared(); + + if distance_squared <= self.radius.powi(2) { + // The point is inside the circle. + point + } else { + // The point is outside the circle. + // Find the closest point on the perimeter of the circle. + let dir_to_point = point / distance_squared.sqrt(); + self.radius * dir_to_point + } + } +} + /// An ellipse primitive #[derive(Clone, Copy, Debug)] pub struct Ellipse { @@ -187,8 +213,10 @@ impl Segment2d { pub fn from_points(point1: Vec2, point2: Vec2) -> (Self, Vec2) { let diff = point2 - point1; let length = diff.length(); + ( - Self::new(Direction2d::from_normalized(diff / length), length), + // We are dividing by the length here, so the vector is normalized. + Self::new(Direction2d::new_unchecked(diff / length), length), (point1 + point2) / 2., ) } @@ -351,6 +379,16 @@ impl Rectangle { half_size: size / 2., } } + + /// Finds the point on the rectangle that is closest to the given `point`. + /// + /// If the point is outside the rectangle, the returned point will be on the perimeter of the rectangle. + /// Otherwise, it will be inside the rectangle and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec2) -> Vec2 { + // Clamp point coordinates to the rectangle + point.clamp(-self.half_size, self.half_size) + } } /// A polygon with N vertices. @@ -477,7 +515,7 @@ mod tests { ); assert_eq!( Direction2d::new_and_length(Vec2::X * 6.5), - Ok((Direction2d::from_normalized(Vec2::X), 6.5)) + Ok((Direction2d::X, 6.5)) ); } @@ -542,4 +580,29 @@ mod tests { < 1e-7, ); } + + #[test] + fn rectangle_closest_point() { + let rectangle = Rectangle::new(2.0, 2.0); + assert_eq!(rectangle.closest_point(Vec2::X * 10.0), Vec2::X); + assert_eq!(rectangle.closest_point(Vec2::NEG_ONE * 10.0), Vec2::NEG_ONE); + assert_eq!( + rectangle.closest_point(Vec2::new(0.25, 0.1)), + Vec2::new(0.25, 0.1) + ); + } + + #[test] + fn circle_closest_point() { + let circle = Circle { radius: 1.0 }; + assert_eq!(circle.closest_point(Vec2::X * 10.0), Vec2::X); + assert_eq!( + circle.closest_point(Vec2::NEG_ONE * 10.0), + Vec2::NEG_ONE.normalize() + ); + assert_eq!( + circle.closest_point(Vec2::new(0.25, 0.1)), + Vec2::new(0.25, 0.1) + ); + } } diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 192b9074a933f..4d270fd8acd1b 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -28,6 +28,17 @@ impl Direction3d { Self::new_and_length(value).map(|(dir, _)| dir) } + /// Create a [`Direction3d`] from a [`Vec3`] that is already normalized. + /// + /// # Warning + /// + /// `value` must be normalized, i.e it's length must be `1.0`. + pub fn new_unchecked(value: Vec3) -> Self { + debug_assert!(value.is_normalized()); + + Self(value) + } + /// Create a direction from a finite, nonzero [`Vec3`], also returning its original length. /// /// Returns [`Err(InvalidDirectionError)`](InvalidDirectionError) if the length @@ -38,7 +49,7 @@ impl Direction3d { direction .map(|dir| (Self(dir), length)) - .map_or(Err(InvalidDirectionError::from_length(length)), Ok) + .ok_or(InvalidDirectionError::from_length(length)) } /// Create a direction from its `x`, `y`, and `z` components. @@ -48,12 +59,6 @@ impl Direction3d { pub fn from_xyz(x: f32, y: f32, z: f32) -> Result { Self::new(Vec3::new(x, y, z)) } - - /// Create a direction from a [`Vec3`] that is already normalized. - pub fn from_normalized(value: Vec3) -> Self { - debug_assert!(value.is_normalized()); - Self(value) - } } impl TryFrom for Direction3d { @@ -86,6 +91,27 @@ pub struct Sphere { } impl Primitive3d for Sphere {} +impl Sphere { + /// Finds the point on the sphere that is closest to the given `point`. + /// + /// If the point is outside the sphere, the returned point will be on the surface of the sphere. + /// Otherwise, it will be inside the sphere and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec3) -> Vec3 { + let distance_squared = point.length_squared(); + + if distance_squared <= self.radius.powi(2) { + // The point is inside the sphere. + point + } else { + // The point is outside the sphere. + // Find the closest point on the surface of the sphere. + let dir_to_point = point / distance_squared.sqrt(); + self.radius * dir_to_point + } + } +} + /// An unbounded plane in 3D space. It forms a separating surface through the origin, /// stretching infinitely far #[derive(Clone, Copy, Debug)] @@ -146,8 +172,10 @@ impl Segment3d { pub fn from_points(point1: Vec3, point2: Vec3) -> (Self, Vec3) { let diff = point2 - point1; let length = diff.length(); + ( - Self::new(Direction3d::from_normalized(diff / length), length), + // We are dividing by the length here, so the vector is normalized. + Self::new(Direction3d::new_unchecked(diff / length), length), (point1 + point2) / 2., ) } @@ -238,6 +266,16 @@ impl Cuboid { half_size: size / 2., } } + + /// Finds the point on the cuboid that is closest to the given `point`. + /// + /// If the point is outside the cuboid, the returned point will be on the surface of the cuboid. + /// Otherwise, it will be inside the cuboid and returned as is. + #[inline(always)] + pub fn closest_point(&self, point: Vec3) -> Vec3 { + // Clamp point coordinates to the cuboid + point.clamp(-self.half_size, self.half_size) + } } /// A cylinder primitive @@ -423,7 +461,32 @@ mod test { ); assert_eq!( Direction3d::new_and_length(Vec3::X * 6.5), - Ok((Direction3d::from_normalized(Vec3::X), 6.5)) + Ok((Direction3d::X, 6.5)) + ); + } + + #[test] + fn cuboid_closest_point() { + let cuboid = Cuboid::new(2.0, 2.0, 2.0); + assert_eq!(cuboid.closest_point(Vec3::X * 10.0), Vec3::X); + assert_eq!(cuboid.closest_point(Vec3::NEG_ONE * 10.0), Vec3::NEG_ONE); + assert_eq!( + cuboid.closest_point(Vec3::new(0.25, 0.1, 0.3)), + Vec3::new(0.25, 0.1, 0.3) + ); + } + + #[test] + fn sphere_closest_point() { + let sphere = Sphere { radius: 1.0 }; + assert_eq!(sphere.closest_point(Vec3::X * 10.0), Vec3::X); + assert_eq!( + sphere.closest_point(Vec3::NEG_ONE * 10.0), + Vec3::NEG_ONE.normalize() + ); + assert_eq!( + sphere.closest_point(Vec3::new(0.25, 0.1, 0.3)), + Vec3::new(0.25, 0.1, 0.3) ); } } diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index cd9f45ba12f9c..d7d76b355b518 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -142,7 +142,7 @@ pub const DEFERRED_LIGHTING_PASS: &str = "deferred_opaque_pbr_lighting_pass_3d"; pub struct DeferredOpaquePass3dPbrLightingNode; impl ViewNode for DeferredOpaquePass3dPbrLightingNode { - type ViewData = ( + type ViewQuery = ( &'static ViewUniformOffset, &'static ViewLightsUniformOffset, &'static ViewFogUniformOffset, @@ -166,7 +166,7 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode { target, deferred_lighting_id_depth_texture, deferred_lighting_pipeline, - ): QueryItem, + ): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let pipeline_cache = world.resource::(); diff --git a/crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl b/crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl index bdc8dbd54008e..345bebfffdaae 100644 --- a/crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl +++ b/crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl @@ -33,7 +33,7 @@ fn deferred_gbuffer_from_pbr_input(in: PbrInput) -> vec4 { var props = deferred_types::pack_unorm3x4_plus_unorm_20_(vec4( in.material.reflectance, in.material.metallic, - diffuse_occlusion, + diffuse_occlusion, in.frag_coord.z)); #else var props = deferred_types::pack_unorm4x8_(vec4( diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_pbr/src/light_probe/environment_map.rs index 0b355b666fcb1..6651d2412044b 100644 --- a/crates/bevy_pbr/src/light_probe/environment_map.rs +++ b/crates/bevy_pbr/src/light_probe/environment_map.rs @@ -185,11 +185,11 @@ pub(crate) enum RenderViewBindGroupEntries<'a> { } impl ExtractInstance for EnvironmentMapIds { - type Data = Read; + type QueryData = Read; - type Filter = (); + type QueryFilter = (); - fn extract(item: QueryItem<'_, Self::Data>) -> Option { + fn extract(item: QueryItem<'_, Self::QueryData>) -> Option { Some(EnvironmentMapIds { diffuse: item.diffuse_map.id(), specular: item.specular_map.id(), diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 9c715751c4156..f8a3e2285eedb 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -414,8 +414,8 @@ type DrawMaterial = ( pub struct SetMaterialBindGroup(PhantomData); impl RenderCommand

for SetMaterialBindGroup { type Param = (SRes>, SRes>); - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index b5393560e2bd6..8856f5b995584 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -906,11 +906,11 @@ pub fn queue_prepass_material_meshes( pub struct SetPrepassViewBindGroup; impl RenderCommand

for SetPrepassViewBindGroup { type Param = SRes; - type ViewData = ( + type ViewQuery = ( Read, Option>, ); - type ItemData = (); + type ItemQuery = (); #[inline] fn render<'w>( diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 674ef668f6ee8..77ad03ea9bc52 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1043,21 +1043,21 @@ pub fn prepare_mesh_bind_group( pub struct SetMeshViewBindGroup; impl RenderCommand

for SetMeshViewBindGroup { type Param = (); - type ViewData = ( + type ViewQuery = ( Read, Read, Read, Read, Read, ); - type ItemData = (); + type ItemQuery = (); #[inline] fn render<'w>( _item: &P, (view_uniform, view_lights, view_fog, view_light_probes, mesh_view_bind_group): ROQueryItem< 'w, - Self::ViewData, + Self::ViewQuery, >, _entity: (), _: SystemParamItem<'w, '_, Self::Param>, @@ -1087,8 +1087,8 @@ impl RenderCommand

for SetMeshBindGroup { SRes, SRes, ); - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( @@ -1157,8 +1157,8 @@ impl RenderCommand

for SetMeshBindGroup { pub struct DrawMesh; impl RenderCommand

for DrawMesh { type Param = (SRes>, SRes); - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( item: &P, diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index cbcca32a23cf4..d9c9b8dc0fea1 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -199,7 +199,7 @@ impl ScreenSpaceAmbientOcclusionQualityLevel { struct SsaoNode {} impl ViewNode for SsaoNode { - type ViewData = ( + type ViewQuery = ( &'static ExtractedCamera, &'static SsaoPipelineId, &'static SsaoBindGroups, @@ -210,7 +210,7 @@ impl ViewNode for SsaoNode { &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (camera, pipeline_id, bind_groups, view_uniform_offset): QueryItem, + (camera, pipeline_id, bind_groups, view_uniform_offset): QueryItem, world: &World, ) -> Result<(), NodeRunError> { let pipelines = world.resource::(); diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 5dcfa9e375289..3d522e9462155 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -201,6 +201,8 @@ impl_reflect_value!(::core::num::NonZeroI8( Serialize, Deserialize )); +impl_reflect_value!(::core::num::Wrapping()); +impl_reflect_value!(::core::num::Saturating()); impl_reflect_value!(::std::sync::Arc); // `Serialize` and `Deserialize` only for platforms supported by serde: diff --git a/crates/bevy_reflect/src/type_uuid_impl.rs b/crates/bevy_reflect/src/type_uuid_impl.rs index 9e614171ef57f..d7f772438631c 100644 --- a/crates/bevy_reflect/src/type_uuid_impl.rs +++ b/crates/bevy_reflect/src/type_uuid_impl.rs @@ -11,7 +11,7 @@ use std::ffi::OsString; use std::{ num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, - NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Saturating, Wrapping, }, ops::{RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}, path::PathBuf, @@ -69,6 +69,8 @@ impl_type_uuid!(NonZeroI16, "8744c2ec8a10491fae40f8bafa58b30d"); impl_type_uuid!(NonZeroU16, "c7b8b60780a6495bab4fda2bdfedabcc"); impl_type_uuid!(NonZeroU8, "635ee104ef7947fb9d7f79dad47255a3"); impl_type_uuid!(NonZeroI8, "2d3f1570b7f64779826d44da5c7ba069"); +impl_type_uuid!(Saturating, "e9d7c5d5b9e94c9c9c8c8c0f5f3c5c5f"); +impl_type_uuid!(Wrapping, "d5b9e94c9c9c8c8c0f5f3c5c5fe9d7c5"); #[cfg(any(unix, windows))] impl_type_uuid!(OsString, "809e7b3c1ea240979ecd832f91eb842a"); macro_rules! impl_tuple { diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index f5724f30d6c3b..003e1aef54c87 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -82,7 +82,7 @@ ddsfile = { version = "0.5.0", optional = true } ktx2 = { version = "0.3.0", optional = true } # For ktx2 supercompression flate2 = { version = "1.0.22", optional = true } -ruzstd = { version = "0.4.0", optional = true } +ruzstd = { version = "0.5.0", optional = true } # For transcoding of UASTC/ETC1S universal formats, and for .basis file support basis-universal = { version = "0.3.0", optional = true } encase = { version = "0.7", features = ["glam"] } diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index 9e750fd57ed77..b1c7a12e0b0bc 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -11,6 +11,7 @@ use syn::{ const UNIFORM_ATTRIBUTE_NAME: Symbol = Symbol("uniform"); const TEXTURE_ATTRIBUTE_NAME: Symbol = Symbol("texture"); +const STORAGE_TEXTURE_ATTRIBUTE_NAME: Symbol = Symbol("storage_texture"); const SAMPLER_ATTRIBUTE_NAME: Symbol = Symbol("sampler"); const STORAGE_ATTRIBUTE_NAME: Symbol = Symbol("storage"); const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data"); @@ -19,6 +20,7 @@ const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data"); enum BindingType { Uniform, Texture, + StorageTexture, Sampler, Storage, } @@ -133,6 +135,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { BindingType::Uniform } else if attr_ident == TEXTURE_ATTRIBUTE_NAME { BindingType::Texture + } else if attr_ident == STORAGE_TEXTURE_ATTRIBUTE_NAME { + BindingType::StorageTexture } else if attr_ident == SAMPLER_ATTRIBUTE_NAME { BindingType::Sampler } else if attr_ident == STORAGE_ATTRIBUTE_NAME { @@ -255,6 +259,45 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { } }); } + BindingType::StorageTexture => { + let StorageTextureAttrs { + dimension, + image_format, + access, + visibility, + } = get_storage_texture_binding_attr(nested_meta_items)?; + + let visibility = + visibility.hygienic_quote("e! { #render_path::render_resource }); + + let fallback_image = get_fallback_image(&render_path, dimension); + + binding_impls.push(quote! { + ( #binding_index, + #render_path::render_resource::OwnedBindingResource::TextureView({ + let handle: Option<&#asset_path::Handle<#render_path::texture::Image>> = (&self.#field_name).into(); + if let Some(handle) = handle { + images.get(handle).ok_or_else(|| #render_path::render_resource::AsBindGroupError::RetryNextUpdate)?.texture_view.clone() + } else { + #fallback_image.texture_view.clone() + } + }) + ) + }); + + binding_layouts.push(quote! { + #render_path::render_resource::BindGroupLayoutEntry { + binding: #binding_index, + visibility: #visibility, + ty: #render_path::render_resource::BindingType::StorageTexture { + access: #render_path::render_resource::StorageTextureAccess::#access, + format: #render_path::render_resource::TextureFormat::#image_format, + view_dimension: #render_path::render_resource::#dimension, + }, + count: None, + } + }); + } BindingType::Texture => { let TextureAttrs { dimension, @@ -585,6 +628,10 @@ impl ShaderStageVisibility { fn vertex_fragment() -> Self { Self::Flags(VisibilityFlags::vertex_fragment()) } + + fn compute() -> Self { + Self::Flags(VisibilityFlags::compute()) + } } impl VisibilityFlags { @@ -595,6 +642,13 @@ impl VisibilityFlags { ..Default::default() } } + + fn compute() -> Self { + Self { + compute: true, + ..Default::default() + } + } } impl ShaderStageVisibility { @@ -741,7 +795,72 @@ impl Default for TextureAttrs { } } +struct StorageTextureAttrs { + dimension: BindingTextureDimension, + // Parsing of the image_format parameter is deferred to the type checker, + // which will error if the format is not member of the TextureFormat enum. + image_format: proc_macro2::TokenStream, + // Parsing of the access parameter is deferred to the type checker, + // which will error if the access is not member of the StorageTextureAccess enum. + access: proc_macro2::TokenStream, + visibility: ShaderStageVisibility, +} + +impl Default for StorageTextureAttrs { + fn default() -> Self { + Self { + dimension: Default::default(), + image_format: quote! { Rgba8Unorm }, + access: quote! { ReadWrite }, + visibility: ShaderStageVisibility::compute(), + } + } +} + +fn get_storage_texture_binding_attr(metas: Vec) -> Result { + let mut storage_texture_attrs = StorageTextureAttrs::default(); + + for meta in metas { + use syn::Meta::{List, NameValue}; + match meta { + // Parse #[storage_texture(0, dimension = "...")]. + NameValue(m) if m.path == DIMENSION => { + let value = get_lit_str(DIMENSION, &m.value)?; + storage_texture_attrs.dimension = get_texture_dimension_value(value)?; + } + // Parse #[storage_texture(0, format = ...))]. + NameValue(m) if m.path == IMAGE_FORMAT => { + storage_texture_attrs.image_format = m.value.into_token_stream(); + } + // Parse #[storage_texture(0, access = ...))]. + NameValue(m) if m.path == ACCESS => { + storage_texture_attrs.access = m.value.into_token_stream(); + } + // Parse #[storage_texture(0, visibility(...))]. + List(m) if m.path == VISIBILITY => { + storage_texture_attrs.visibility = get_visibility_flag_value(&m)?; + } + NameValue(m) => { + return Err(Error::new_spanned( + m.path, + "Not a valid name. Available attributes: `dimension`, `image_format`, `access`.", + )); + } + _ => { + return Err(Error::new_spanned( + meta, + "Not a name value pair: `foo = \"...\"`", + )); + } + } + } + + Ok(storage_texture_attrs) +} + const DIMENSION: Symbol = Symbol("dimension"); +const IMAGE_FORMAT: Symbol = Symbol("image_format"); +const ACCESS: Symbol = Symbol("access"); const SAMPLE_TYPE: Symbol = Symbol("sample_type"); const FILTERABLE: Symbol = Symbol("filterable"); const MULTISAMPLED: Symbol = Symbol("multisampled"); diff --git a/crates/bevy_render/macros/src/extract_component.rs b/crates/bevy_render/macros/src/extract_component.rs index 8e0f5f55860f4..80d1aa57ca5b5 100644 --- a/crates/bevy_render/macros/src/extract_component.rs +++ b/crates/bevy_render/macros/src/extract_component.rs @@ -38,12 +38,12 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream { TokenStream::from(quote! { impl #impl_generics #bevy_render_path::extract_component::ExtractComponent for #struct_name #type_generics #where_clause { - type Data = &'static Self; + type QueryData = &'static Self; - type Filter = #filter; + type QueryFilter = #filter; type Out = Self; - fn extract_component(item: #bevy_ecs_path::query::QueryItem<'_, Self::Data>) -> Option { + fn extract_component(item: #bevy_ecs_path::query::QueryItem<'_, Self::QueryData>) -> Option { Some(item.clone()) } } diff --git a/crates/bevy_render/macros/src/lib.rs b/crates/bevy_render/macros/src/lib.rs index 89eec6b220c9a..97126ba830bf4 100644 --- a/crates/bevy_render/macros/src/lib.rs +++ b/crates/bevy_render/macros/src/lib.rs @@ -51,7 +51,7 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream { #[proc_macro_derive( AsBindGroup, - attributes(uniform, texture, sampler, bind_group_data, storage) + attributes(uniform, storage_texture, texture, sampler, bind_group_data, storage) )] pub fn derive_as_bind_group(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 63ef625a170e3..98be77b2b9689 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -36,9 +36,9 @@ impl DynamicUniformIndex { /// in the [`ExtractSchedule`] step. pub trait ExtractComponent: Component { /// ECS [`ReadOnlyQueryData`] to fetch the components to extract. - type Data: ReadOnlyQueryData; + type QueryData: ReadOnlyQueryData; /// Filters the entities with additional constraints. - type Filter: QueryFilter; + type QueryFilter: QueryFilter; /// The output from extraction. /// @@ -58,7 +58,7 @@ pub trait ExtractComponent: Component { // type Out: Component = Self; /// Defines how the component is transferred into the "render world". - fn extract_component(item: QueryItem<'_, Self::Data>) -> Option; + fn extract_component(item: QueryItem<'_, Self::QueryData>) -> Option; } /// This plugin prepares the components of the corresponding type for the GPU @@ -195,12 +195,12 @@ impl Plugin for ExtractComponentPlugin { } impl ExtractComponent for Handle { - type Data = Read>; - type Filter = (); + type QueryData = Read>; + type QueryFilter = (); type Out = Handle; #[inline] - fn extract_component(handle: QueryItem<'_, Self::Data>) -> Option { + fn extract_component(handle: QueryItem<'_, Self::QueryData>) -> Option { Some(handle.clone_weak()) } } @@ -209,7 +209,7 @@ impl ExtractComponent for Handle { fn extract_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { @@ -225,7 +225,7 @@ fn extract_components( fn extract_visible_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, view_visibility, query_item) in &query { diff --git a/crates/bevy_render/src/extract_instances.rs b/crates/bevy_render/src/extract_instances.rs index 0b088e4607d7e..96fcfea7cb84e 100644 --- a/crates/bevy_render/src/extract_instances.rs +++ b/crates/bevy_render/src/extract_instances.rs @@ -29,12 +29,12 @@ use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp}; /// higher-performance because it avoids the ECS overhead. pub trait ExtractInstance: Send + Sync + Sized + 'static { /// ECS [`ReadOnlyQueryData`] to fetch the components to extract. - type Data: ReadOnlyQueryData; + type QueryData: ReadOnlyQueryData; /// Filters the entities with additional constraints. - type Filter: QueryFilter; + type QueryFilter: QueryFilter; /// Defines how the component is transferred into the "render world". - fn extract(item: QueryItem<'_, Self::Data>) -> Option; + fn extract(item: QueryItem<'_, Self::QueryData>) -> Option; } /// This plugin extracts one or more components into the "render world" as @@ -107,7 +107,7 @@ where fn extract_all( mut extracted_instances: ResMut>, - query: Extract>, + query: Extract>, ) where EI: ExtractInstance, { @@ -121,7 +121,7 @@ fn extract_all( fn extract_visible( mut extracted_instances: ResMut>, - query: Extract>, + query: Extract>, ) where EI: ExtractInstance, { @@ -139,10 +139,10 @@ impl ExtractInstance for AssetId where A: Asset, { - type Data = Read>; - type Filter = (); + type QueryData = Read>; + type QueryFilter = (); - fn extract(item: QueryItem<'_, Self::Data>) -> Option { + fn extract(item: QueryItem<'_, Self::QueryData>) -> Option { Some(item.id()) } } diff --git a/crates/bevy_render/src/render_graph/node.rs b/crates/bevy_render/src/render_graph/node.rs index 4d83dad643675..ef28794f9f49f 100644 --- a/crates/bevy_render/src/render_graph/node.rs +++ b/crates/bevy_render/src/render_graph/node.rs @@ -342,7 +342,7 @@ impl Node for RunGraphOnViewNode { pub trait ViewNode { /// The query that will be used on the view entity. /// It is guaranteed to run on the view entity, so there's no need for a filter - type ViewData: ReadOnlyQueryData; + type ViewQuery: ReadOnlyQueryData; /// Updates internal node state using the current render [`World`] prior to the run method. fn update(&mut self, _world: &mut World) {} @@ -354,7 +354,7 @@ pub trait ViewNode { &self, graph: &mut RenderGraphContext, render_context: &mut RenderContext, - view_query: QueryItem, + view_query: QueryItem, world: &World, ) -> Result<(), NodeRunError>; } @@ -364,7 +364,7 @@ pub trait ViewNode { /// /// This [`Node`] exists to help reduce boilerplate when making a render node that runs on a view. pub struct ViewNodeRunner { - view_query: QueryState, + view_query: QueryState, node: N, } diff --git a/crates/bevy_render/src/render_phase/draw.rs b/crates/bevy_render/src/render_phase/draw.rs index 9837799fbcc3e..b293ca620c948 100644 --- a/crates/bevy_render/src/render_phase/draw.rs +++ b/crates/bevy_render/src/render_phase/draw.rs @@ -142,8 +142,8 @@ impl DrawFunctions

{ /// Compared to the draw function the required ECS data is fetched automatically /// (by the [`RenderCommandState`]) from the render world. /// Therefore the three types [`Param`](RenderCommand::Param), -/// [`ViewData`](RenderCommand::ViewData) and -/// [`ItemData`](RenderCommand::ItemData) are used. +/// [`ViewQuery`](RenderCommand::ViewQuery) and +/// [`ItemQuery`](RenderCommand::ItemQuery) are used. /// They specify which information is required to execute the render command. /// /// Multiple render commands can be combined together by wrapping them in a tuple. @@ -185,19 +185,19 @@ pub trait RenderCommand { /// The view entity refers to the camera, or shadow-casting light, etc. from which the phase /// item will be rendered from. /// All components have to be accessed read only. - type ViewData: ReadOnlyQueryData; + type ViewQuery: ReadOnlyQueryData; /// Specifies the ECS data of the item entity required by [`RenderCommand::render`]. /// /// The item is the entity that will be rendered for the corresponding view. /// All components have to be accessed read only. - type ItemData: ReadOnlyQueryData; + type ItemQuery: ReadOnlyQueryData; /// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups, /// issuing draw calls, etc.) via the [`TrackedRenderPass`]. fn render<'w>( item: &P, - view: ROQueryItem<'w, Self::ViewData>, - entity: ROQueryItem<'w, Self::ItemData>, + view: ROQueryItem<'w, Self::ViewQuery>, + entity: ROQueryItem<'w, Self::ItemQuery>, param: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult; @@ -213,14 +213,14 @@ macro_rules! render_command_tuple_impl { ($(($name: ident, $view: ident, $entity: ident)),*) => { impl),*> RenderCommand

for ($($name,)*) { type Param = ($($name::Param,)*); - type ViewData = ($($name::ViewData,)*); - type ItemData = ($($name::ItemData,)*); + type ViewQuery = ($($name::ViewQuery,)*); + type ItemQuery = ($($name::ItemQuery,)*); #[allow(non_snake_case)] fn render<'w>( _item: &P, - ($($view,)*): ROQueryItem<'w, Self::ViewData>, - ($($entity,)*): ROQueryItem<'w, Self::ItemData>, + ($($view,)*): ROQueryItem<'w, Self::ViewQuery>, + ($($entity,)*): ROQueryItem<'w, Self::ItemQuery>, ($($name,)*): SystemParamItem<'w, '_, Self::Param>, _pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -237,12 +237,12 @@ all_tuples!(render_command_tuple_impl, 0, 15, C, V, E); /// Wraps a [`RenderCommand`] into a state so that it can be used as a [`Draw`] function. /// -/// The [`RenderCommand::Param`], [`RenderCommand::ViewData`] and -/// [`RenderCommand::ItemData`] are fetched from the ECS and passed to the command. +/// The [`RenderCommand::Param`], [`RenderCommand::ViewQuery`] and +/// [`RenderCommand::ItemQuery`] are fetched from the ECS and passed to the command. pub struct RenderCommandState> { state: SystemState, - view: QueryState, - entity: QueryState, + view: QueryState, + entity: QueryState, } impl> RenderCommandState { diff --git a/crates/bevy_render/src/render_phase/mod.rs b/crates/bevy_render/src/render_phase/mod.rs index 5cf9976ec4d93..df804bfad10b9 100644 --- a/crates/bevy_render/src/render_phase/mod.rs +++ b/crates/bevy_render/src/render_phase/mod.rs @@ -196,8 +196,8 @@ pub struct SetItemPipeline; impl RenderCommand

for SetItemPipeline { type Param = SRes; - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( item: &P, diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index fc4f5c0d7d608..03e98abbd8818 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -87,6 +87,8 @@ impl Deref for BindGroup { /// values: Vec, /// #[storage(4, read_only, buffer)] /// buffer: Buffer, +/// #[storage_texture(5)] +/// storage_texture: Handle, /// } /// ``` /// @@ -97,6 +99,7 @@ impl Deref for BindGroup { /// @group(2) @binding(1) var color_texture: texture_2d; /// @group(2) @binding(2) var color_sampler: sampler; /// @group(2) @binding(3) var values: array; +/// @group(2) @binding(5) var storage_texture: texture_storage_2d; /// ``` /// Note that the "group" index is determined by the usage context. It is not defined in [`AsBindGroup`]. For example, in Bevy material bind groups /// are generally bound to group 2. @@ -123,6 +126,19 @@ impl Deref for BindGroup { /// | `multisampled` = ... | `true`, `false` | `false` | /// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `vertex`, `fragment` | /// +/// * `storage_texture(BINDING_INDEX, arguments)` +/// * This field's [`Handle`](bevy_asset::Handle) will be used to look up the matching [`Texture`](crate::render_resource::Texture) +/// GPU resource, which will be bound as a storage texture in shaders. The field will be assumed to implement [`Into>>`]. In practice, +/// most fields should be a [`Handle`](bevy_asset::Handle) or [`Option>`]. If the value of an [`Option>`] is +/// [`None`], the [`FallbackImage`] resource will be used instead. +/// +/// | Arguments | Values | Default | +/// |------------------------|--------------------------------------------------------------------------------------------|---------------| +/// | `dimension` = "..." | `"1d"`, `"2d"`, `"2d_array"`, `"3d"`, `"cube"`, `"cube_array"` | `"2d"` | +/// | `image_format` = ... | any member of [`TextureFormat`](crate::render_resource::TextureFormat) | `Rgba8Unorm` | +/// | `access` = ... | any member of [`StorageTextureAccess`](crate::render_resource::StorageTextureAccess) | `ReadWrite` | +/// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `compute` | +/// /// * `sampler(BINDING_INDEX, arguments)` /// * This field's [`Handle`](bevy_asset::Handle) will be used to look up the matching [`Sampler`] GPU /// resource, which will be bound as a sampler in shaders. The field will be assumed to implement [`Into>>`]. In practice, diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 702d9e7d7173c..07626d47a5c9f 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -330,8 +330,8 @@ impl RenderCommand

SRes>, SRes>, ); - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 9817e67f91cb5..4b9c9943dc793 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -613,13 +613,13 @@ pub fn prepare_mesh2d_view_bind_groups( pub struct SetMesh2dViewBindGroup; impl RenderCommand

for SetMesh2dViewBindGroup { type Param = (); - type ViewData = (Read, Read); - type ItemData = (); + type ViewQuery = (Read, Read); + type ItemQuery = (); #[inline] fn render<'w>( _item: &P, - (view_uniform, mesh2d_view_bind_group): ROQueryItem<'w, Self::ViewData>, + (view_uniform, mesh2d_view_bind_group): ROQueryItem<'w, Self::ViewQuery>, _view: (), _param: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, @@ -633,8 +633,8 @@ impl RenderCommand

for SetMesh2dViewBindGroup; impl RenderCommand

for SetMesh2dBindGroup { type Param = SRes; - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( @@ -662,8 +662,8 @@ impl RenderCommand

for SetMesh2dBindGroup { pub struct DrawMesh2d; impl RenderCommand

for DrawMesh2d { type Param = (SRes>, SRes); - type ViewData = (); - type ItemData = (); + type ViewQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 60c96584146e4..df319a7857e34 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -734,8 +734,8 @@ pub type DrawSprite = ( pub struct SetSpriteViewBindGroup; impl RenderCommand

for SetSpriteViewBindGroup { type Param = SRes; - type ViewData = Read; - type ItemData = (); + type ViewQuery = Read; + type ItemQuery = (); fn render<'w>( _item: &P, @@ -755,8 +755,8 @@ impl RenderCommand

for SetSpriteViewBindGroup; impl RenderCommand

for SetSpriteTextureBindGroup { type Param = SRes; - type ViewData = (); - type ItemData = Read; + type ViewQuery = (); + type ItemQuery = Read; fn render<'w>( _item: &P, @@ -782,8 +782,8 @@ impl RenderCommand

for SetSpriteTextureBindGrou pub struct DrawSpriteBatch; impl RenderCommand

for DrawSpriteBatch { type Param = SRes; - type ViewData = (); - type ItemData = Read; + type ViewQuery = (); + type ItemQuery = Read; fn render<'w>( _item: &P, diff --git a/crates/bevy_sprite/src/texture_atlas_builder.rs b/crates/bevy_sprite/src/texture_atlas_builder.rs index 3a8eae428ce0c..116982719bff1 100644 --- a/crates/bevy_sprite/src/texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/texture_atlas_builder.rs @@ -84,6 +84,8 @@ impl TextureAtlasBuilder { } /// Adds a texture to be copied to the texture atlas. + /// + /// The insertion order will reflect the index of the added texture in the finished texture atlas. pub fn add_texture(&mut self, image_id: AssetId, texture: &Image) { self.textures_to_place .push((image_id, texture.texture_descriptor.size)); @@ -150,6 +152,7 @@ impl TextureAtlasBuilder { /// Consumes the builder, and returns the newly created texture handle and /// the assciated atlas layout. /// + /// Assigns indices to the textures based on the insertion order. /// Internally it copies all rectangles from the textures and copies them /// into a new texture. /// It is not useful to hold a strong handle to the texture afterwards else @@ -259,7 +262,10 @@ impl TextureAtlasBuilder { let mut texture_rects = Vec::with_capacity(rect_placements.packed_locations().len()); let mut texture_ids = HashMap::default(); - for (image_id, (_, packed_location)) in rect_placements.packed_locations() { + // We iterate through the textures to place to respect the insertion order for the texture indices + for (image_id, _) in &self.textures_to_place { + let (_, packed_location) = rect_placements.packed_locations().get(image_id).unwrap(); + let texture = textures.get(*image_id).unwrap(); let min = Vec2::new(packed_location.x() as f32, packed_location.y() as f32); let max = min diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index d55a9476b0076..f34b98c91d213 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -360,7 +360,8 @@ impl TaskPool { unsafe { mem::transmute(external_executor) }; // SAFETY: As above, all futures must complete in this function so we can change the lifetime let scope_executor: &'env ThreadExecutor<'env> = unsafe { mem::transmute(scope_executor) }; - let spawned: ConcurrentQueue> = ConcurrentQueue::unbounded(); + let spawned: ConcurrentQueue>>> = + ConcurrentQueue::unbounded(); // shadow the variable so that the owned value cannot be used for the rest of the function // SAFETY: As above, all futures must complete in this function so we can change the lifetime let spawned: &'env ConcurrentQueue< diff --git a/crates/bevy_transform/src/commands.rs b/crates/bevy_transform/src/commands.rs index 5f34ead144682..1a2f0d4c8abfb 100644 --- a/crates/bevy_transform/src/commands.rs +++ b/crates/bevy_transform/src/commands.rs @@ -85,7 +85,7 @@ pub trait BuildChildrenTransformExt { /// (during [`apply_deferred`](bevy_ecs::schedule::apply_deferred)). fn remove_parent_in_place(&mut self) -> &mut Self; } -impl<'w, 's, 'a> BuildChildrenTransformExt for EntityCommands<'w, 's, 'a> { +impl BuildChildrenTransformExt for EntityCommands<'_> { fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self { let child = self.id(); self.commands().add(PushChildInPlace { child, parent }); diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index 0b993cd9fc79b..a38a14d234c1e 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -155,8 +155,8 @@ pub type DrawUi = ( pub struct SetUiViewBindGroup; impl RenderCommand

for SetUiViewBindGroup { type Param = SRes; - type ViewData = Read; - type ItemData = (); + type ViewQuery = Read; + type ItemQuery = (); fn render<'w>( _item: &P, @@ -176,8 +176,8 @@ impl RenderCommand

for SetUiViewBindGroup { pub struct SetUiTextureBindGroup; impl RenderCommand

for SetUiTextureBindGroup { type Param = SRes; - type ViewData = (); - type ItemData = Read; + type ViewQuery = (); + type ItemQuery = Read; #[inline] fn render<'w>( @@ -195,8 +195,8 @@ impl RenderCommand

for SetUiTextureBindGroup pub struct DrawUiNode; impl RenderCommand

for DrawUiNode { type Param = SRes; - type ViewData = (); - type ItemData = Read; + type ViewQuery = (); + type ItemQuery = Read; #[inline] fn render<'w>( diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 9f17afc930ae6..2900560a6d059 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -263,8 +263,8 @@ pub type DrawUiMaterial = ( pub struct SetMatUiViewBindGroup(PhantomData); impl RenderCommand

for SetMatUiViewBindGroup { type Param = SRes>; - type ViewData = Read; - type ItemData = (); + type ViewQuery = Read; + type ItemQuery = (); fn render<'w>( _item: &P, @@ -287,13 +287,13 @@ impl RenderCommand

for SetUiMaterialBindGroup { type Param = SRes>; - type ViewData = (); - type ItemData = Read>; + type ViewQuery = (); + type ItemQuery = Read>; fn render<'w>( _item: &P, _view: (), - material_handle: ROQueryItem<'_, Self::ItemData>, + material_handle: ROQueryItem<'_, Self::ItemQuery>, materials: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -308,8 +308,8 @@ impl RenderCommand

pub struct DrawUiMaterialNode(PhantomData); impl RenderCommand

for DrawUiMaterialNode { type Param = SRes>; - type ViewData = (); - type ItemData = Read>; + type ViewQuery = (); + type ItemQuery = Read>; #[inline] fn render<'w>( diff --git a/crates/bevy_winit/src/converters.rs b/crates/bevy_winit/src/converters.rs index f7d2e8a209b6a..5cc2c03475528 100644 --- a/crates/bevy_winit/src/converters.rs +++ b/crates/bevy_winit/src/converters.rs @@ -7,6 +7,7 @@ use bevy_input::{ }; use bevy_math::Vec2; use bevy_window::{CursorIcon, EnabledButtons, WindowLevel, WindowTheme}; +use winit::keyboard::{Key, NamedKey, NativeKey}; pub fn convert_keyboard_input( keyboard_input: &winit::event::KeyEvent, @@ -15,6 +16,7 @@ pub fn convert_keyboard_input( KeyboardInput { state: convert_element_state(keyboard_input.state), key_code: convert_physical_key_code(keyboard_input.physical_key), + logical_key: convert_logical_key(&keyboard_input.logical_key), window, } } @@ -283,6 +285,348 @@ pub fn convert_physical_key_code(virtual_key_code: winit::keyboard::PhysicalKey) } } +pub fn convert_logical_key(logical_key_code: &winit::keyboard::Key) -> bevy_input::keyboard::Key { + match logical_key_code { + Key::Character(s) => bevy_input::keyboard::Key::Character(s.clone()), + Key::Unidentified(nk) => bevy_input::keyboard::Key::Unidentified(convert_native_key(nk)), + Key::Dead(c) => bevy_input::keyboard::Key::Dead(c.to_owned()), + Key::Named(NamedKey::Alt) => bevy_input::keyboard::Key::Alt, + Key::Named(NamedKey::AltGraph) => bevy_input::keyboard::Key::AltGraph, + Key::Named(NamedKey::CapsLock) => bevy_input::keyboard::Key::CapsLock, + Key::Named(NamedKey::Control) => bevy_input::keyboard::Key::Control, + Key::Named(NamedKey::Fn) => bevy_input::keyboard::Key::Fn, + Key::Named(NamedKey::FnLock) => bevy_input::keyboard::Key::FnLock, + Key::Named(NamedKey::NumLock) => bevy_input::keyboard::Key::NumLock, + Key::Named(NamedKey::ScrollLock) => bevy_input::keyboard::Key::ScrollLock, + Key::Named(NamedKey::Shift) => bevy_input::keyboard::Key::Shift, + Key::Named(NamedKey::Symbol) => bevy_input::keyboard::Key::Symbol, + Key::Named(NamedKey::SymbolLock) => bevy_input::keyboard::Key::SymbolLock, + Key::Named(NamedKey::Meta) => bevy_input::keyboard::Key::Meta, + Key::Named(NamedKey::Hyper) => bevy_input::keyboard::Key::Hyper, + Key::Named(NamedKey::Super) => bevy_input::keyboard::Key::Super, + Key::Named(NamedKey::Enter) => bevy_input::keyboard::Key::Enter, + Key::Named(NamedKey::Tab) => bevy_input::keyboard::Key::Tab, + Key::Named(NamedKey::Space) => bevy_input::keyboard::Key::Space, + Key::Named(NamedKey::ArrowDown) => bevy_input::keyboard::Key::ArrowDown, + Key::Named(NamedKey::ArrowLeft) => bevy_input::keyboard::Key::ArrowLeft, + Key::Named(NamedKey::ArrowRight) => bevy_input::keyboard::Key::ArrowRight, + Key::Named(NamedKey::ArrowUp) => bevy_input::keyboard::Key::ArrowUp, + Key::Named(NamedKey::End) => bevy_input::keyboard::Key::End, + Key::Named(NamedKey::Home) => bevy_input::keyboard::Key::Home, + Key::Named(NamedKey::PageDown) => bevy_input::keyboard::Key::PageDown, + Key::Named(NamedKey::PageUp) => bevy_input::keyboard::Key::PageUp, + Key::Named(NamedKey::Backspace) => bevy_input::keyboard::Key::Backspace, + Key::Named(NamedKey::Clear) => bevy_input::keyboard::Key::Clear, + Key::Named(NamedKey::Copy) => bevy_input::keyboard::Key::Copy, + Key::Named(NamedKey::CrSel) => bevy_input::keyboard::Key::CrSel, + Key::Named(NamedKey::Cut) => bevy_input::keyboard::Key::Cut, + Key::Named(NamedKey::Delete) => bevy_input::keyboard::Key::Delete, + Key::Named(NamedKey::EraseEof) => bevy_input::keyboard::Key::EraseEof, + Key::Named(NamedKey::ExSel) => bevy_input::keyboard::Key::ExSel, + Key::Named(NamedKey::Insert) => bevy_input::keyboard::Key::Insert, + Key::Named(NamedKey::Paste) => bevy_input::keyboard::Key::Paste, + Key::Named(NamedKey::Redo) => bevy_input::keyboard::Key::Redo, + Key::Named(NamedKey::Undo) => bevy_input::keyboard::Key::Undo, + Key::Named(NamedKey::Accept) => bevy_input::keyboard::Key::Accept, + Key::Named(NamedKey::Again) => bevy_input::keyboard::Key::Again, + Key::Named(NamedKey::Attn) => bevy_input::keyboard::Key::Attn, + Key::Named(NamedKey::Cancel) => bevy_input::keyboard::Key::Cancel, + Key::Named(NamedKey::ContextMenu) => bevy_input::keyboard::Key::ContextMenu, + Key::Named(NamedKey::Escape) => bevy_input::keyboard::Key::Escape, + Key::Named(NamedKey::Execute) => bevy_input::keyboard::Key::Execute, + Key::Named(NamedKey::Find) => bevy_input::keyboard::Key::Find, + Key::Named(NamedKey::Help) => bevy_input::keyboard::Key::Help, + Key::Named(NamedKey::Pause) => bevy_input::keyboard::Key::Pause, + Key::Named(NamedKey::Play) => bevy_input::keyboard::Key::Play, + Key::Named(NamedKey::Props) => bevy_input::keyboard::Key::Props, + Key::Named(NamedKey::Select) => bevy_input::keyboard::Key::Select, + Key::Named(NamedKey::ZoomIn) => bevy_input::keyboard::Key::ZoomIn, + Key::Named(NamedKey::ZoomOut) => bevy_input::keyboard::Key::ZoomOut, + Key::Named(NamedKey::BrightnessDown) => bevy_input::keyboard::Key::BrightnessDown, + Key::Named(NamedKey::BrightnessUp) => bevy_input::keyboard::Key::BrightnessUp, + Key::Named(NamedKey::Eject) => bevy_input::keyboard::Key::Eject, + Key::Named(NamedKey::LogOff) => bevy_input::keyboard::Key::LogOff, + Key::Named(NamedKey::Power) => bevy_input::keyboard::Key::Power, + Key::Named(NamedKey::PowerOff) => bevy_input::keyboard::Key::PowerOff, + Key::Named(NamedKey::PrintScreen) => bevy_input::keyboard::Key::PrintScreen, + Key::Named(NamedKey::Hibernate) => bevy_input::keyboard::Key::Hibernate, + Key::Named(NamedKey::Standby) => bevy_input::keyboard::Key::Standby, + Key::Named(NamedKey::WakeUp) => bevy_input::keyboard::Key::WakeUp, + Key::Named(NamedKey::AllCandidates) => bevy_input::keyboard::Key::AllCandidates, + Key::Named(NamedKey::Alphanumeric) => bevy_input::keyboard::Key::Alphanumeric, + Key::Named(NamedKey::CodeInput) => bevy_input::keyboard::Key::CodeInput, + Key::Named(NamedKey::Compose) => bevy_input::keyboard::Key::Compose, + Key::Named(NamedKey::Convert) => bevy_input::keyboard::Key::Convert, + Key::Named(NamedKey::FinalMode) => bevy_input::keyboard::Key::FinalMode, + Key::Named(NamedKey::GroupFirst) => bevy_input::keyboard::Key::GroupFirst, + Key::Named(NamedKey::GroupLast) => bevy_input::keyboard::Key::GroupLast, + Key::Named(NamedKey::GroupNext) => bevy_input::keyboard::Key::GroupNext, + Key::Named(NamedKey::GroupPrevious) => bevy_input::keyboard::Key::GroupPrevious, + Key::Named(NamedKey::ModeChange) => bevy_input::keyboard::Key::ModeChange, + Key::Named(NamedKey::NextCandidate) => bevy_input::keyboard::Key::NextCandidate, + Key::Named(NamedKey::NonConvert) => bevy_input::keyboard::Key::NonConvert, + Key::Named(NamedKey::PreviousCandidate) => bevy_input::keyboard::Key::PreviousCandidate, + Key::Named(NamedKey::Process) => bevy_input::keyboard::Key::Process, + Key::Named(NamedKey::SingleCandidate) => bevy_input::keyboard::Key::SingleCandidate, + Key::Named(NamedKey::HangulMode) => bevy_input::keyboard::Key::HangulMode, + Key::Named(NamedKey::HanjaMode) => bevy_input::keyboard::Key::HanjaMode, + Key::Named(NamedKey::JunjaMode) => bevy_input::keyboard::Key::JunjaMode, + Key::Named(NamedKey::Eisu) => bevy_input::keyboard::Key::Eisu, + Key::Named(NamedKey::Hankaku) => bevy_input::keyboard::Key::Hankaku, + Key::Named(NamedKey::Hiragana) => bevy_input::keyboard::Key::Hiragana, + Key::Named(NamedKey::HiraganaKatakana) => bevy_input::keyboard::Key::HiraganaKatakana, + Key::Named(NamedKey::KanaMode) => bevy_input::keyboard::Key::KanaMode, + Key::Named(NamedKey::KanjiMode) => bevy_input::keyboard::Key::KanjiMode, + Key::Named(NamedKey::Katakana) => bevy_input::keyboard::Key::Katakana, + Key::Named(NamedKey::Romaji) => bevy_input::keyboard::Key::Romaji, + Key::Named(NamedKey::Zenkaku) => bevy_input::keyboard::Key::Zenkaku, + Key::Named(NamedKey::ZenkakuHankaku) => bevy_input::keyboard::Key::ZenkakuHankaku, + Key::Named(NamedKey::Soft1) => bevy_input::keyboard::Key::Soft1, + Key::Named(NamedKey::Soft2) => bevy_input::keyboard::Key::Soft2, + Key::Named(NamedKey::Soft3) => bevy_input::keyboard::Key::Soft3, + Key::Named(NamedKey::Soft4) => bevy_input::keyboard::Key::Soft4, + Key::Named(NamedKey::ChannelDown) => bevy_input::keyboard::Key::ChannelDown, + Key::Named(NamedKey::ChannelUp) => bevy_input::keyboard::Key::ChannelUp, + Key::Named(NamedKey::Close) => bevy_input::keyboard::Key::Close, + Key::Named(NamedKey::MailForward) => bevy_input::keyboard::Key::MailForward, + Key::Named(NamedKey::MailReply) => bevy_input::keyboard::Key::MailReply, + Key::Named(NamedKey::MailSend) => bevy_input::keyboard::Key::MailSend, + Key::Named(NamedKey::MediaClose) => bevy_input::keyboard::Key::MediaClose, + Key::Named(NamedKey::MediaFastForward) => bevy_input::keyboard::Key::MediaFastForward, + Key::Named(NamedKey::MediaPause) => bevy_input::keyboard::Key::MediaPause, + Key::Named(NamedKey::MediaPlay) => bevy_input::keyboard::Key::MediaPlay, + Key::Named(NamedKey::MediaPlayPause) => bevy_input::keyboard::Key::MediaPlayPause, + Key::Named(NamedKey::MediaRecord) => bevy_input::keyboard::Key::MediaRecord, + Key::Named(NamedKey::MediaRewind) => bevy_input::keyboard::Key::MediaRewind, + Key::Named(NamedKey::MediaStop) => bevy_input::keyboard::Key::MediaStop, + Key::Named(NamedKey::MediaTrackNext) => bevy_input::keyboard::Key::MediaTrackNext, + Key::Named(NamedKey::MediaTrackPrevious) => bevy_input::keyboard::Key::MediaTrackPrevious, + Key::Named(NamedKey::New) => bevy_input::keyboard::Key::New, + Key::Named(NamedKey::Open) => bevy_input::keyboard::Key::Open, + Key::Named(NamedKey::Print) => bevy_input::keyboard::Key::Print, + Key::Named(NamedKey::Save) => bevy_input::keyboard::Key::Save, + Key::Named(NamedKey::SpellCheck) => bevy_input::keyboard::Key::SpellCheck, + Key::Named(NamedKey::Key11) => bevy_input::keyboard::Key::Key11, + Key::Named(NamedKey::Key12) => bevy_input::keyboard::Key::Key12, + Key::Named(NamedKey::AudioBalanceLeft) => bevy_input::keyboard::Key::AudioBalanceLeft, + Key::Named(NamedKey::AudioBalanceRight) => bevy_input::keyboard::Key::AudioBalanceRight, + Key::Named(NamedKey::AudioBassBoostDown) => bevy_input::keyboard::Key::AudioBassBoostDown, + Key::Named(NamedKey::AudioBassBoostToggle) => { + bevy_input::keyboard::Key::AudioBassBoostToggle + } + Key::Named(NamedKey::AudioBassBoostUp) => bevy_input::keyboard::Key::AudioBassBoostUp, + Key::Named(NamedKey::AudioFaderFront) => bevy_input::keyboard::Key::AudioFaderFront, + Key::Named(NamedKey::AudioFaderRear) => bevy_input::keyboard::Key::AudioFaderRear, + Key::Named(NamedKey::AudioSurroundModeNext) => { + bevy_input::keyboard::Key::AudioSurroundModeNext + } + Key::Named(NamedKey::AudioTrebleDown) => bevy_input::keyboard::Key::AudioTrebleDown, + Key::Named(NamedKey::AudioTrebleUp) => bevy_input::keyboard::Key::AudioTrebleUp, + Key::Named(NamedKey::AudioVolumeDown) => bevy_input::keyboard::Key::AudioVolumeDown, + Key::Named(NamedKey::AudioVolumeUp) => bevy_input::keyboard::Key::AudioVolumeUp, + Key::Named(NamedKey::AudioVolumeMute) => bevy_input::keyboard::Key::AudioVolumeMute, + Key::Named(NamedKey::MicrophoneToggle) => bevy_input::keyboard::Key::MicrophoneToggle, + Key::Named(NamedKey::MicrophoneVolumeDown) => { + bevy_input::keyboard::Key::MicrophoneVolumeDown + } + Key::Named(NamedKey::MicrophoneVolumeUp) => bevy_input::keyboard::Key::MicrophoneVolumeUp, + Key::Named(NamedKey::MicrophoneVolumeMute) => { + bevy_input::keyboard::Key::MicrophoneVolumeMute + } + Key::Named(NamedKey::SpeechCorrectionList) => { + bevy_input::keyboard::Key::SpeechCorrectionList + } + Key::Named(NamedKey::SpeechInputToggle) => bevy_input::keyboard::Key::SpeechInputToggle, + Key::Named(NamedKey::LaunchApplication1) => bevy_input::keyboard::Key::LaunchApplication1, + Key::Named(NamedKey::LaunchApplication2) => bevy_input::keyboard::Key::LaunchApplication2, + Key::Named(NamedKey::LaunchCalendar) => bevy_input::keyboard::Key::LaunchCalendar, + Key::Named(NamedKey::LaunchContacts) => bevy_input::keyboard::Key::LaunchContacts, + Key::Named(NamedKey::LaunchMail) => bevy_input::keyboard::Key::LaunchMail, + Key::Named(NamedKey::LaunchMediaPlayer) => bevy_input::keyboard::Key::LaunchMediaPlayer, + Key::Named(NamedKey::LaunchMusicPlayer) => bevy_input::keyboard::Key::LaunchMusicPlayer, + Key::Named(NamedKey::LaunchPhone) => bevy_input::keyboard::Key::LaunchPhone, + Key::Named(NamedKey::LaunchScreenSaver) => bevy_input::keyboard::Key::LaunchScreenSaver, + Key::Named(NamedKey::LaunchSpreadsheet) => bevy_input::keyboard::Key::LaunchSpreadsheet, + Key::Named(NamedKey::LaunchWebBrowser) => bevy_input::keyboard::Key::LaunchWebBrowser, + Key::Named(NamedKey::LaunchWebCam) => bevy_input::keyboard::Key::LaunchWebCam, + Key::Named(NamedKey::LaunchWordProcessor) => bevy_input::keyboard::Key::LaunchWordProcessor, + Key::Named(NamedKey::BrowserBack) => bevy_input::keyboard::Key::BrowserBack, + Key::Named(NamedKey::BrowserFavorites) => bevy_input::keyboard::Key::BrowserFavorites, + Key::Named(NamedKey::BrowserForward) => bevy_input::keyboard::Key::BrowserForward, + Key::Named(NamedKey::BrowserHome) => bevy_input::keyboard::Key::BrowserHome, + Key::Named(NamedKey::BrowserRefresh) => bevy_input::keyboard::Key::BrowserRefresh, + Key::Named(NamedKey::BrowserSearch) => bevy_input::keyboard::Key::BrowserSearch, + Key::Named(NamedKey::BrowserStop) => bevy_input::keyboard::Key::BrowserStop, + Key::Named(NamedKey::AppSwitch) => bevy_input::keyboard::Key::AppSwitch, + Key::Named(NamedKey::Call) => bevy_input::keyboard::Key::Call, + Key::Named(NamedKey::Camera) => bevy_input::keyboard::Key::Camera, + Key::Named(NamedKey::CameraFocus) => bevy_input::keyboard::Key::CameraFocus, + Key::Named(NamedKey::EndCall) => bevy_input::keyboard::Key::EndCall, + Key::Named(NamedKey::GoBack) => bevy_input::keyboard::Key::GoBack, + Key::Named(NamedKey::GoHome) => bevy_input::keyboard::Key::GoHome, + Key::Named(NamedKey::HeadsetHook) => bevy_input::keyboard::Key::HeadsetHook, + Key::Named(NamedKey::LastNumberRedial) => bevy_input::keyboard::Key::LastNumberRedial, + Key::Named(NamedKey::Notification) => bevy_input::keyboard::Key::Notification, + Key::Named(NamedKey::MannerMode) => bevy_input::keyboard::Key::MannerMode, + Key::Named(NamedKey::VoiceDial) => bevy_input::keyboard::Key::VoiceDial, + Key::Named(NamedKey::TV) => bevy_input::keyboard::Key::TV, + Key::Named(NamedKey::TV3DMode) => bevy_input::keyboard::Key::TV3DMode, + Key::Named(NamedKey::TVAntennaCable) => bevy_input::keyboard::Key::TVAntennaCable, + Key::Named(NamedKey::TVAudioDescription) => bevy_input::keyboard::Key::TVAudioDescription, + Key::Named(NamedKey::TVAudioDescriptionMixDown) => { + bevy_input::keyboard::Key::TVAudioDescriptionMixDown + } + Key::Named(NamedKey::TVAudioDescriptionMixUp) => { + bevy_input::keyboard::Key::TVAudioDescriptionMixUp + } + Key::Named(NamedKey::TVContentsMenu) => bevy_input::keyboard::Key::TVContentsMenu, + Key::Named(NamedKey::TVDataService) => bevy_input::keyboard::Key::TVDataService, + Key::Named(NamedKey::TVInput) => bevy_input::keyboard::Key::TVInput, + Key::Named(NamedKey::TVInputComponent1) => bevy_input::keyboard::Key::TVInputComponent1, + Key::Named(NamedKey::TVInputComponent2) => bevy_input::keyboard::Key::TVInputComponent2, + Key::Named(NamedKey::TVInputComposite1) => bevy_input::keyboard::Key::TVInputComposite1, + Key::Named(NamedKey::TVInputComposite2) => bevy_input::keyboard::Key::TVInputComposite2, + Key::Named(NamedKey::TVInputHDMI1) => bevy_input::keyboard::Key::TVInputHDMI1, + Key::Named(NamedKey::TVInputHDMI2) => bevy_input::keyboard::Key::TVInputHDMI2, + Key::Named(NamedKey::TVInputHDMI3) => bevy_input::keyboard::Key::TVInputHDMI3, + Key::Named(NamedKey::TVInputHDMI4) => bevy_input::keyboard::Key::TVInputHDMI4, + Key::Named(NamedKey::TVInputVGA1) => bevy_input::keyboard::Key::TVInputVGA1, + Key::Named(NamedKey::TVMediaContext) => bevy_input::keyboard::Key::TVMediaContext, + Key::Named(NamedKey::TVNetwork) => bevy_input::keyboard::Key::TVNetwork, + Key::Named(NamedKey::TVNumberEntry) => bevy_input::keyboard::Key::TVNumberEntry, + Key::Named(NamedKey::TVPower) => bevy_input::keyboard::Key::TVPower, + Key::Named(NamedKey::TVRadioService) => bevy_input::keyboard::Key::TVRadioService, + Key::Named(NamedKey::TVSatellite) => bevy_input::keyboard::Key::TVSatellite, + Key::Named(NamedKey::TVSatelliteBS) => bevy_input::keyboard::Key::TVSatelliteBS, + Key::Named(NamedKey::TVSatelliteCS) => bevy_input::keyboard::Key::TVSatelliteCS, + Key::Named(NamedKey::TVSatelliteToggle) => bevy_input::keyboard::Key::TVSatelliteToggle, + Key::Named(NamedKey::TVTerrestrialAnalog) => bevy_input::keyboard::Key::TVTerrestrialAnalog, + Key::Named(NamedKey::TVTerrestrialDigital) => { + bevy_input::keyboard::Key::TVTerrestrialDigital + } + Key::Named(NamedKey::TVTimer) => bevy_input::keyboard::Key::TVTimer, + Key::Named(NamedKey::AVRInput) => bevy_input::keyboard::Key::AVRInput, + Key::Named(NamedKey::AVRPower) => bevy_input::keyboard::Key::AVRPower, + Key::Named(NamedKey::ColorF0Red) => bevy_input::keyboard::Key::ColorF0Red, + Key::Named(NamedKey::ColorF1Green) => bevy_input::keyboard::Key::ColorF1Green, + Key::Named(NamedKey::ColorF2Yellow) => bevy_input::keyboard::Key::ColorF2Yellow, + Key::Named(NamedKey::ColorF3Blue) => bevy_input::keyboard::Key::ColorF3Blue, + Key::Named(NamedKey::ColorF4Grey) => bevy_input::keyboard::Key::ColorF4Grey, + Key::Named(NamedKey::ColorF5Brown) => bevy_input::keyboard::Key::ColorF5Brown, + Key::Named(NamedKey::ClosedCaptionToggle) => bevy_input::keyboard::Key::ClosedCaptionToggle, + Key::Named(NamedKey::Dimmer) => bevy_input::keyboard::Key::Dimmer, + Key::Named(NamedKey::DisplaySwap) => bevy_input::keyboard::Key::DisplaySwap, + Key::Named(NamedKey::DVR) => bevy_input::keyboard::Key::DVR, + Key::Named(NamedKey::Exit) => bevy_input::keyboard::Key::Exit, + Key::Named(NamedKey::FavoriteClear0) => bevy_input::keyboard::Key::FavoriteClear0, + Key::Named(NamedKey::FavoriteClear1) => bevy_input::keyboard::Key::FavoriteClear1, + Key::Named(NamedKey::FavoriteClear2) => bevy_input::keyboard::Key::FavoriteClear2, + Key::Named(NamedKey::FavoriteClear3) => bevy_input::keyboard::Key::FavoriteClear3, + Key::Named(NamedKey::FavoriteRecall0) => bevy_input::keyboard::Key::FavoriteRecall0, + Key::Named(NamedKey::FavoriteRecall1) => bevy_input::keyboard::Key::FavoriteRecall1, + Key::Named(NamedKey::FavoriteRecall2) => bevy_input::keyboard::Key::FavoriteRecall2, + Key::Named(NamedKey::FavoriteRecall3) => bevy_input::keyboard::Key::FavoriteRecall3, + Key::Named(NamedKey::FavoriteStore0) => bevy_input::keyboard::Key::FavoriteStore0, + Key::Named(NamedKey::FavoriteStore1) => bevy_input::keyboard::Key::FavoriteStore1, + Key::Named(NamedKey::FavoriteStore2) => bevy_input::keyboard::Key::FavoriteStore2, + Key::Named(NamedKey::FavoriteStore3) => bevy_input::keyboard::Key::FavoriteStore3, + Key::Named(NamedKey::Guide) => bevy_input::keyboard::Key::Guide, + Key::Named(NamedKey::GuideNextDay) => bevy_input::keyboard::Key::GuideNextDay, + Key::Named(NamedKey::GuidePreviousDay) => bevy_input::keyboard::Key::GuidePreviousDay, + Key::Named(NamedKey::Info) => bevy_input::keyboard::Key::Info, + Key::Named(NamedKey::InstantReplay) => bevy_input::keyboard::Key::InstantReplay, + Key::Named(NamedKey::Link) => bevy_input::keyboard::Key::Link, + Key::Named(NamedKey::ListProgram) => bevy_input::keyboard::Key::ListProgram, + Key::Named(NamedKey::LiveContent) => bevy_input::keyboard::Key::LiveContent, + Key::Named(NamedKey::Lock) => bevy_input::keyboard::Key::Lock, + Key::Named(NamedKey::MediaApps) => bevy_input::keyboard::Key::MediaApps, + Key::Named(NamedKey::MediaAudioTrack) => bevy_input::keyboard::Key::MediaAudioTrack, + Key::Named(NamedKey::MediaLast) => bevy_input::keyboard::Key::MediaLast, + Key::Named(NamedKey::MediaSkipBackward) => bevy_input::keyboard::Key::MediaSkipBackward, + Key::Named(NamedKey::MediaSkipForward) => bevy_input::keyboard::Key::MediaSkipForward, + Key::Named(NamedKey::MediaStepBackward) => bevy_input::keyboard::Key::MediaStepBackward, + Key::Named(NamedKey::MediaStepForward) => bevy_input::keyboard::Key::MediaStepForward, + Key::Named(NamedKey::MediaTopMenu) => bevy_input::keyboard::Key::MediaTopMenu, + Key::Named(NamedKey::NavigateIn) => bevy_input::keyboard::Key::NavigateIn, + Key::Named(NamedKey::NavigateNext) => bevy_input::keyboard::Key::NavigateNext, + Key::Named(NamedKey::NavigateOut) => bevy_input::keyboard::Key::NavigateOut, + Key::Named(NamedKey::NavigatePrevious) => bevy_input::keyboard::Key::NavigatePrevious, + Key::Named(NamedKey::NextFavoriteChannel) => bevy_input::keyboard::Key::NextFavoriteChannel, + Key::Named(NamedKey::NextUserProfile) => bevy_input::keyboard::Key::NextUserProfile, + Key::Named(NamedKey::OnDemand) => bevy_input::keyboard::Key::OnDemand, + Key::Named(NamedKey::Pairing) => bevy_input::keyboard::Key::Pairing, + Key::Named(NamedKey::PinPDown) => bevy_input::keyboard::Key::PinPDown, + Key::Named(NamedKey::PinPMove) => bevy_input::keyboard::Key::PinPMove, + Key::Named(NamedKey::PinPToggle) => bevy_input::keyboard::Key::PinPToggle, + Key::Named(NamedKey::PinPUp) => bevy_input::keyboard::Key::PinPUp, + Key::Named(NamedKey::PlaySpeedDown) => bevy_input::keyboard::Key::PlaySpeedDown, + Key::Named(NamedKey::PlaySpeedReset) => bevy_input::keyboard::Key::PlaySpeedReset, + Key::Named(NamedKey::PlaySpeedUp) => bevy_input::keyboard::Key::PlaySpeedUp, + Key::Named(NamedKey::RandomToggle) => bevy_input::keyboard::Key::RandomToggle, + Key::Named(NamedKey::RcLowBattery) => bevy_input::keyboard::Key::RcLowBattery, + Key::Named(NamedKey::RecordSpeedNext) => bevy_input::keyboard::Key::RecordSpeedNext, + Key::Named(NamedKey::RfBypass) => bevy_input::keyboard::Key::RfBypass, + Key::Named(NamedKey::ScanChannelsToggle) => bevy_input::keyboard::Key::ScanChannelsToggle, + Key::Named(NamedKey::ScreenModeNext) => bevy_input::keyboard::Key::ScreenModeNext, + Key::Named(NamedKey::Settings) => bevy_input::keyboard::Key::Settings, + Key::Named(NamedKey::SplitScreenToggle) => bevy_input::keyboard::Key::SplitScreenToggle, + Key::Named(NamedKey::STBInput) => bevy_input::keyboard::Key::STBInput, + Key::Named(NamedKey::STBPower) => bevy_input::keyboard::Key::STBPower, + Key::Named(NamedKey::Subtitle) => bevy_input::keyboard::Key::Subtitle, + Key::Named(NamedKey::Teletext) => bevy_input::keyboard::Key::Teletext, + Key::Named(NamedKey::VideoModeNext) => bevy_input::keyboard::Key::VideoModeNext, + Key::Named(NamedKey::Wink) => bevy_input::keyboard::Key::Wink, + Key::Named(NamedKey::ZoomToggle) => bevy_input::keyboard::Key::ZoomToggle, + Key::Named(NamedKey::F1) => bevy_input::keyboard::Key::F1, + Key::Named(NamedKey::F2) => bevy_input::keyboard::Key::F2, + Key::Named(NamedKey::F3) => bevy_input::keyboard::Key::F3, + Key::Named(NamedKey::F4) => bevy_input::keyboard::Key::F4, + Key::Named(NamedKey::F5) => bevy_input::keyboard::Key::F5, + Key::Named(NamedKey::F6) => bevy_input::keyboard::Key::F6, + Key::Named(NamedKey::F7) => bevy_input::keyboard::Key::F7, + Key::Named(NamedKey::F8) => bevy_input::keyboard::Key::F8, + Key::Named(NamedKey::F9) => bevy_input::keyboard::Key::F9, + Key::Named(NamedKey::F10) => bevy_input::keyboard::Key::F10, + Key::Named(NamedKey::F11) => bevy_input::keyboard::Key::F11, + Key::Named(NamedKey::F12) => bevy_input::keyboard::Key::F12, + Key::Named(NamedKey::F13) => bevy_input::keyboard::Key::F13, + Key::Named(NamedKey::F14) => bevy_input::keyboard::Key::F14, + Key::Named(NamedKey::F15) => bevy_input::keyboard::Key::F15, + Key::Named(NamedKey::F16) => bevy_input::keyboard::Key::F16, + Key::Named(NamedKey::F17) => bevy_input::keyboard::Key::F17, + Key::Named(NamedKey::F18) => bevy_input::keyboard::Key::F18, + Key::Named(NamedKey::F19) => bevy_input::keyboard::Key::F19, + Key::Named(NamedKey::F20) => bevy_input::keyboard::Key::F20, + Key::Named(NamedKey::F21) => bevy_input::keyboard::Key::F21, + Key::Named(NamedKey::F22) => bevy_input::keyboard::Key::F22, + Key::Named(NamedKey::F23) => bevy_input::keyboard::Key::F23, + Key::Named(NamedKey::F24) => bevy_input::keyboard::Key::F24, + Key::Named(NamedKey::F25) => bevy_input::keyboard::Key::F25, + Key::Named(NamedKey::F26) => bevy_input::keyboard::Key::F26, + Key::Named(NamedKey::F27) => bevy_input::keyboard::Key::F27, + Key::Named(NamedKey::F28) => bevy_input::keyboard::Key::F28, + Key::Named(NamedKey::F29) => bevy_input::keyboard::Key::F29, + Key::Named(NamedKey::F30) => bevy_input::keyboard::Key::F30, + Key::Named(NamedKey::F31) => bevy_input::keyboard::Key::F31, + Key::Named(NamedKey::F32) => bevy_input::keyboard::Key::F32, + Key::Named(NamedKey::F33) => bevy_input::keyboard::Key::F33, + Key::Named(NamedKey::F34) => bevy_input::keyboard::Key::F34, + Key::Named(NamedKey::F35) => bevy_input::keyboard::Key::F35, + _ => todo!(), + } +} + +pub fn convert_native_key(native_key: &NativeKey) -> bevy_input::keyboard::NativeKey { + match native_key { + NativeKey::Unidentified => bevy_input::keyboard::NativeKey::Unidentified, + NativeKey::Android(v) => bevy_input::keyboard::NativeKey::Android(*v), + NativeKey::MacOS(v) => bevy_input::keyboard::NativeKey::MacOS(*v), + NativeKey::Windows(v) => bevy_input::keyboard::NativeKey::Windows(*v), + NativeKey::Xkb(v) => bevy_input::keyboard::NativeKey::Xkb(*v), + NativeKey::Web(v) => bevy_input::keyboard::NativeKey::Web(v.clone()), + } +} + pub fn convert_cursor_icon(cursor_icon: CursorIcon) -> winit::window::CursorIcon { match cursor_icon { CursorIcon::Crosshair => winit::window::CursorIcon::Crosshair, diff --git a/examples/3d/3d_gizmos.rs b/examples/3d/3d_gizmos.rs index 182342c55f465..f2bf53a5247f2 100644 --- a/examples/3d/3d_gizmos.rs +++ b/examples/3d/3d_gizmos.rs @@ -2,6 +2,7 @@ use std::f32::consts::PI; +use bevy::math::primitives::Direction3d; use bevy::prelude::*; fn main() { @@ -96,10 +97,10 @@ fn system(mut gizmos: Gizmos, mut my_gizmos: Gizmos, time: Res size, _ => 0, }; + // Register our new component to the world with a layout specified by it's size // SAFETY: [u64] is Send + Sync let id = world.init_component_with_descriptor(unsafe { ComponentDescriptor::new_with_layout( @@ -100,44 +101,45 @@ fn main() { } "s" => { let mut to_insert_ids = Vec::new(); - let mut to_insert_ptr = Vec::new(); + let mut to_insert_data = Vec::new(); rest.split(',').for_each(|component| { let mut component = component.split_whitespace(); let Some(name) = component.next() else { return; }; + + // Get the id for the component with the given name let Some(&id) = component_names.get(name) else { println!("Component {} does not exist", name); return; }; + + // Calculate the length for the array based on the layout created for this component id let info = world.components().get_info(id).unwrap(); let len = info.layout().size() / std::mem::size_of::(); let mut values: Vec = component .take(len) .filter_map(|value| value.parse::().ok()) .collect(); + values.resize(len, 0); - // SAFETY: - // - All components will be interpreted as [u64] - // - len and layout are taken directly from the component descriptor - let ptr = unsafe { - let data = std::alloc::alloc_zeroed(info.layout()).cast::(); - data.copy_from(values.as_mut_ptr(), values.len()); - let non_null = NonNull::new_unchecked(data.cast()); - OwningPtr::new(non_null) - }; - + // Collect the id and array to be inserted onto our entity to_insert_ids.push(id); - to_insert_ptr.push(ptr); + to_insert_data.push(values); }); let mut entity = world.spawn_empty(); + + // Construct an `OwningPtr` for each component in `to_insert_data` + let to_insert_ptr = to_owning_ptrs(&mut to_insert_data); + // SAFETY: // - Component ids have been taken from the same world - // - The pointer with the correct layout + // - Each array is created to the layout specified in the world unsafe { entity.insert_by_ids(&to_insert_ids, to_insert_ptr.into_iter()); } + println!("Entity spawned with id: {:?}", entity.id()); } "q" => { @@ -162,6 +164,8 @@ fn main() { len, ) }; + + // If we have write access, increment each value once if filtered_entity.access().has_write(id) { data.iter_mut().for_each(|data| { *data += 1; @@ -181,6 +185,24 @@ fn main() { } } +// Constructs `OwningPtr` for each item in `components` +// By sharing the lifetime of `components` with the resulting ptrs we ensure we don't drop the data before use +fn to_owning_ptrs(components: &mut [Vec]) -> Vec> { + components + .iter_mut() + .map(|data| { + let ptr = data.as_mut_ptr(); + // SAFETY: + // - Pointers are guaranteed to be non-null + // - Memory pointed to won't be dropped until `components` is dropped + unsafe { + let non_null = NonNull::new_unchecked(ptr.cast()); + OwningPtr::new(non_null) + } + }) + .collect() +} + fn parse_term( str: &str, builder: &mut QueryBuilder, @@ -189,10 +211,12 @@ fn parse_term( let mut matched = false; let str = str.trim(); match str.chars().next() { + // Optional term Some('?') => { builder.optional(|b| parse_term(&str[1..], b, components)); matched = true; } + // Reference term Some('&') => { let mut parts = str.split_whitespace(); let first = parts.next().unwrap(); @@ -208,6 +232,7 @@ fn parse_term( matched = true; } } + // With term Some(_) => { if let Some(&id) = components.get(str) { builder.with_id(id); diff --git a/examples/shader/compute_shader_game_of_life.rs b/examples/shader/compute_shader_game_of_life.rs index df16d67b178a4..8248e4e9b14f3 100644 --- a/examples/shader/compute_shader_game_of_life.rs +++ b/examples/shader/compute_shader_game_of_life.rs @@ -10,7 +10,7 @@ use bevy::{ render_asset::RenderAssetPersistencePolicy, render_asset::RenderAssets, render_graph::{self, RenderGraph}, - render_resource::{binding_types::texture_storage_2d, *}, + render_resource::*, renderer::{RenderContext, RenderDevice}, Render, RenderApp, RenderSet, }, @@ -65,7 +65,7 @@ fn setup(mut commands: Commands, mut images: ResMut>) { }); commands.spawn(Camera2dBundle::default()); - commands.insert_resource(GameOfLifeImage(image)); + commands.insert_resource(GameOfLifeImage { texture: image }); } pub struct GameOfLifeComputePlugin; @@ -95,8 +95,11 @@ impl Plugin for GameOfLifeComputePlugin { } } -#[derive(Resource, Clone, Deref, ExtractResource)] -struct GameOfLifeImage(Handle); +#[derive(Resource, Clone, Deref, ExtractResource, AsBindGroup)] +struct GameOfLifeImage { + #[storage_texture(0, image_format = Rgba8Unorm, access = ReadWrite)] + texture: Handle, +} #[derive(Resource)] struct GameOfLifeImageBindGroup(BindGroup); @@ -108,7 +111,7 @@ fn prepare_bind_group( game_of_life_image: Res, render_device: Res, ) { - let view = gpu_images.get(&game_of_life_image.0).unwrap(); + let view = gpu_images.get(&game_of_life_image.texture).unwrap(); let bind_group = render_device.create_bind_group( None, &pipeline.texture_bind_group_layout, @@ -126,13 +129,8 @@ pub struct GameOfLifePipeline { impl FromWorld for GameOfLifePipeline { fn from_world(world: &mut World) -> Self { - let texture_bind_group_layout = world.resource::().create_bind_group_layout( - None, - &BindGroupLayoutEntries::single( - ShaderStages::COMPUTE, - texture_storage_2d(TextureFormat::Rgba8Unorm, StorageTextureAccess::ReadWrite), - ), - ); + let render_device = world.resource::(); + let texture_bind_group_layout = GameOfLifeImage::bind_group_layout(render_device); let shader = world .resource::() .load("shaders/game_of_life.wgsl"); diff --git a/examples/shader/post_processing.rs b/examples/shader/post_processing.rs index e266fa310d204..f2d15486b9e78 100644 --- a/examples/shader/post_processing.rs +++ b/examples/shader/post_processing.rs @@ -116,7 +116,7 @@ impl ViewNode for PostProcessNode { // but it's not a normal system so we need to define it manually. // // This query will only run on the view entity - type ViewData = ( + type ViewQuery = ( &'static ViewTarget, // This makes sure the node only runs on cameras with the PostProcessSettings component &'static PostProcessSettings, @@ -133,7 +133,7 @@ impl ViewNode for PostProcessNode { &self, _graph: &mut RenderGraphContext, render_context: &mut RenderContext, - (view_target, _post_process_settings): QueryItem, + (view_target, _post_process_settings): QueryItem, world: &World, ) -> Result<(), NodeRunError> { // Get the pipeline resource that contains the global data we need diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 3a40d7fa694ea..8828a76aae0c6 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -68,11 +68,11 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { struct InstanceMaterialData(Vec); impl ExtractComponent for InstanceMaterialData { - type Data = &'static InstanceMaterialData; - type Filter = (); + type QueryData = &'static InstanceMaterialData; + type QueryFilter = (); type Out = Self; - fn extract_component(item: QueryItem<'_, Self::Data>) -> Option { + fn extract_component(item: QueryItem<'_, Self::QueryData>) -> Option { Some(InstanceMaterialData(item.0.clone())) } } @@ -237,8 +237,8 @@ pub struct DrawMeshInstanced; impl RenderCommand

for DrawMeshInstanced { type Param = (SRes>, SRes); - type ViewData = (); - type ItemData = Read; + type ViewQuery = (); + type ItemQuery = Read; #[inline] fn render<'w>( diff --git a/examples/tools/gamepad_viewer.rs b/examples/tools/gamepad_viewer.rs index 359dbcff22c9a..ee5a537d47665 100644 --- a/examples/tools/gamepad_viewer.rs +++ b/examples/tools/gamepad_viewer.rs @@ -21,12 +21,10 @@ const BUTTONS_Y: f32 = 80.; const STICKS_X: f32 = 150.; const STICKS_Y: f32 = -135.; -const NORMAL_BUTTON_COLOR: Color = Color::rgb(0.2, 0.2, 0.2); +const NORMAL_BUTTON_COLOR: Color = Color::rgb(0.3, 0.3, 0.3); const ACTIVE_BUTTON_COLOR: Color = Color::PURPLE; const LIVE_COLOR: Color = Color::rgb(0.4, 0.4, 0.4); -const DEAD_COLOR: Color = Color::rgb(0.3, 0.3, 0.3); -const EXTENT_COLOR: Color = Color::rgb(0.3, 0.3, 0.3); -const TEXT_COLOR: Color = Color::WHITE; +const DEAD_COLOR: Color = Color::rgb(0.13, 0.13, 0.13); #[derive(Component, Deref)] struct ReactTo(GamepadButtonType); @@ -290,7 +288,7 @@ fn setup_sticks( parent.spawn(SpriteBundle { sprite: Sprite { custom_size: Some(Vec2::splat(STICK_BOUNDS_SIZE * 2.)), - color: EXTENT_COLOR, + color: DEAD_COLOR, ..default() }, ..default() @@ -318,7 +316,6 @@ fn setup_sticks( // text let style = TextStyle { font_size: 16., - color: TEXT_COLOR, ..default() }; parent.spawn(( @@ -349,7 +346,7 @@ fn setup_sticks( mesh: meshes.circle.clone(), material: materials.normal.clone(), transform: Transform::from_xyz(0., 0., 5.) - .with_scale(Vec2::splat(0.2).extend(1.)), + .with_scale(Vec2::splat(0.15).extend(1.)), ..default() }, MoveWithAxes { @@ -400,7 +397,6 @@ fn setup_triggers( format!("{:.3}", 0.), TextStyle { font_size: 16., - color: TEXT_COLOR, ..default() }, ), @@ -424,22 +420,30 @@ fn setup_triggers( } fn setup_connected(mut commands: Commands) { - let style = TextStyle { - color: TEXT_COLOR, - font_size: 30., + let text_style = TextStyle { + font_size: 20., ..default() }; commands.spawn(( - TextBundle::from_sections([ - TextSection { - value: "Connected Gamepads:\n".to_string(), - style: style.clone(), - }, - TextSection { - value: "None".to_string(), - style, + TextBundle { + text: Text::from_sections([ + TextSection { + value: "Connected Gamepads:\n".to_string(), + style: text_style.clone(), + }, + TextSection { + value: "None".to_string(), + style: text_style, + }, + ]), + style: Style { + position_type: PositionType::Absolute, + top: Val::Px(12.), + left: Val::Px(12.), + ..default() }, - ]), + ..default() + }, ConnectedGamepadsText, )); }