mirror of
https://github.com/bevyengine/bevy
synced 2024-11-23 13:13:49 +00:00
Merge branch 'main' into avoid-vec-push
This commit is contained in:
commit
930fa50c1e
92 changed files with 291 additions and 154 deletions
|
@ -2,7 +2,7 @@
|
|||
name: Performance Regression
|
||||
about: Bevy running slowly after upgrading? Report a performance regression.
|
||||
title: ''
|
||||
labels: C-Bug, C-Performance, C-Regression, S-Needs-Triage
|
||||
labels: C-Bug, C-Performance, P-Regression, S-Needs-Triage
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
|
|
2
.github/workflows/validation-jobs.yml
vendored
2
.github/workflows/validation-jobs.yml
vendored
|
@ -244,7 +244,7 @@ jobs:
|
|||
|
||||
- name: First Wasm build
|
||||
run: |
|
||||
cargo build --release --example ui --target wasm32-unknown-unknown
|
||||
cargo build --release --example testbed_ui --target wasm32-unknown-unknown
|
||||
|
||||
- name: Run examples
|
||||
shell: bash
|
||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -474,6 +474,7 @@ hyper = { version = "1", features = ["server", "http1"] }
|
|||
http-body-util = "0.1"
|
||||
anyhow = "1"
|
||||
macro_rules_attribute = "0.2"
|
||||
accesskit = "0.17"
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||
smol = "2"
|
||||
|
@ -3136,17 +3137,6 @@ description = "Demonstrates how to control the relative depth (z-position) of UI
|
|||
category = "UI (User Interface)"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "ui"
|
||||
path = "examples/ui/ui.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.ui]
|
||||
name = "UI"
|
||||
description = "Illustrates various features of Bevy UI"
|
||||
category = "UI (User Interface)"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "ui_scaling"
|
||||
path = "examples/ui/ui_scaling.rs"
|
||||
|
@ -3857,6 +3847,13 @@ doc-scrape-examples = true
|
|||
[package.metadata.example.testbed_3d]
|
||||
hidden = true
|
||||
|
||||
[[example]]
|
||||
name = "testbed_ui"
|
||||
path = "examples/testbed/ui.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.testbed_ui]
|
||||
hidden = true
|
||||
|
||||
[[example]]
|
||||
name = "testbed_ui_layout_rounding"
|
||||
|
|
|
@ -6,13 +6,18 @@
|
|||
)]
|
||||
|
||||
//! Accessibility for Bevy
|
||||
//!
|
||||
//! As of Bevy version 0.15 `accesskit` is no longer re-exported from this crate.
|
||||
//!
|
||||
//! If you need to use `accesskit`, you will need to add it as a separate dependency in your `Cargo.toml`.
|
||||
//!
|
||||
//! Make sure to use the same version of `accesskit` as Bevy.
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
pub use accesskit;
|
||||
use accesskit::Node;
|
||||
use bevy_app::Plugin;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
|
|
|
@ -746,7 +746,15 @@ impl WeightsCurveEvaluator {
|
|||
None => {
|
||||
self.blend_register_blend_weight = Some(weight_to_blend);
|
||||
self.blend_register_morph_target_weights.clear();
|
||||
self.blend_register_morph_target_weights.extend(stack_iter);
|
||||
|
||||
// In the additive case, the values pushed onto the blend register need
|
||||
// to be scaled by the weight.
|
||||
if additive {
|
||||
self.blend_register_morph_target_weights
|
||||
.extend(stack_iter.map(|m| m * weight_to_blend));
|
||||
} else {
|
||||
self.blend_register_morph_target_weights.extend(stack_iter);
|
||||
}
|
||||
}
|
||||
|
||||
Some(ref mut current_weight) => {
|
||||
|
@ -877,7 +885,9 @@ where
|
|||
} = self.stack.pop().unwrap();
|
||||
|
||||
match self.blend_register.take() {
|
||||
None => self.blend_register = Some((value_to_blend, weight_to_blend)),
|
||||
None => {
|
||||
self.initialize_blend_register(value_to_blend, weight_to_blend, additive);
|
||||
}
|
||||
Some((mut current_value, mut current_weight)) => {
|
||||
current_weight += weight_to_blend;
|
||||
|
||||
|
@ -912,6 +922,22 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_blend_register(&mut self, value: A, weight: f32, additive: bool) {
|
||||
if additive {
|
||||
let scaled_value = A::blend(
|
||||
[BlendInput {
|
||||
weight,
|
||||
value,
|
||||
additive: true,
|
||||
}]
|
||||
.into_iter(),
|
||||
);
|
||||
self.blend_register = Some((scaled_value, weight));
|
||||
} else {
|
||||
self.blend_register = Some((value, weight));
|
||||
}
|
||||
}
|
||||
|
||||
fn push_blend_register(
|
||||
&mut self,
|
||||
weight: f32,
|
||||
|
|
|
@ -217,9 +217,8 @@ pub enum AnimationNodeType {
|
|||
/// additively.
|
||||
///
|
||||
/// The weights of all the children of this node are *not* normalized to
|
||||
/// 1.0. Rather, the first child is used as a base, ignoring its weight,
|
||||
/// while the others are multiplied by their respective weights and then
|
||||
/// added in sequence to the base.
|
||||
/// 1.0. Rather, each child is multiplied by its respective weight and
|
||||
/// added in sequence.
|
||||
///
|
||||
/// Add nodes are primarily useful for superimposing an animation for a
|
||||
/// portion of a rig on top of the main animation. For example, an add node
|
||||
|
|
0
crates/bevy_animation/src/lib.rs
Executable file → Normal file
0
crates/bevy_animation/src/lib.rs
Executable file → Normal file
|
@ -264,6 +264,17 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl AudioPlayer<AudioSource> {
|
||||
/// Creates a new [`AudioPlayer`] with the given [`Handle<AudioSource>`].
|
||||
///
|
||||
/// For convenience reasons, this hard-codes the [`AudioSource`] type. If you want to
|
||||
/// initialize an [`AudioPlayer`] with a different type, just initialize it directly using normal
|
||||
/// tuple struct syntax.
|
||||
pub fn new(source: Handle<AudioSource>) -> Self {
|
||||
Self(source)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bundle for playing a sound.
|
||||
///
|
||||
/// Insert this bundle onto an entity to trigger a sound source to begin playing.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
//!
|
||||
//! fn play_background_audio(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
//! commands.spawn((
|
||||
//! AudioPlayer::<AudioSource>(asset_server.load("background_audio.ogg")),
|
||||
//! AudioPlayer::new(asset_server.load("background_audio.ogg")),
|
||||
//! PlaybackSettings::LOOP,
|
||||
//! ));
|
||||
//! }
|
||||
|
|
|
@ -89,6 +89,7 @@ impl SpecializedComputePipeline for AutoExposurePipeline {
|
|||
AutoExposurePass::Average => "compute_average".into(),
|
||||
},
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ impl SpecializedRenderPipeline for BlitPipeline {
|
|||
..Default::default()
|
||||
},
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,6 +233,7 @@ impl SpecializedRenderPipeline for CasPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,6 +160,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
|
|||
}),
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
|
||||
Self {
|
||||
|
|
|
@ -806,6 +806,7 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline {
|
|||
},
|
||||
targets,
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,6 +196,7 @@ impl SpecializedRenderPipeline for FxaaPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ impl SpecializedRenderPipeline for MotionBlurPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,6 +208,7 @@ fn specialize_oit_resolve_pipeline(
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ impl SpecializedRenderPipeline for PostProcessingPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,6 +233,7 @@ impl SpecializedRenderPipeline for SkyboxPipeline {
|
|||
write_mask: ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
|
|||
entry_point: "fragment".into(),
|
||||
targets: prepass_target_descriptors(key.normal_prepass, true, false),
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -512,6 +512,7 @@ impl SpecializedRenderPipeline for SmaaEdgeDetectionPipeline {
|
|||
bias: default(),
|
||||
}),
|
||||
multisample: MultisampleState::default(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -571,6 +572,7 @@ impl SpecializedRenderPipeline for SmaaBlendingWeightCalculationPipeline {
|
|||
bias: default(),
|
||||
}),
|
||||
multisample: MultisampleState::default(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -607,6 +609,7 @@ impl SpecializedRenderPipeline for SmaaNeighborhoodBlendingPipeline {
|
|||
primitive: PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@ impl SpecializedRenderPipeline for TaaPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -307,6 +307,7 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1961,13 +1961,13 @@ pub enum ScheduleBuildError {
|
|||
#[display("System dependencies contain cycle(s).\n{_0}")]
|
||||
DependencyCycle(String),
|
||||
/// Tried to order a system (set) relative to a system set it belongs to.
|
||||
#[display("`{0}` and `{_1}` have both `in_set` and `before`-`after` relationships (these might be transitive). This combination is unsolvable as a system cannot run before or after a set it belongs to.")]
|
||||
#[display("`{_0}` and `{_1}` have both `in_set` and `before`-`after` relationships (these might be transitive). This combination is unsolvable as a system cannot run before or after a set it belongs to.")]
|
||||
CrossDependency(String, String),
|
||||
/// Tried to order system sets that share systems.
|
||||
#[display("`{0}` and `{_1}` have a `before`-`after` relationship (which may be transitive) but share systems.")]
|
||||
#[display("`{_0}` and `{_1}` have a `before`-`after` relationship (which may be transitive) but share systems.")]
|
||||
SetsHaveOrderButIntersect(String, String),
|
||||
/// Tried to order a system (set) relative to all instances of some system function.
|
||||
#[display("Tried to order against `{0}` in a schedule that has more than one `{0}` instance. `{_0}` is a `SystemTypeSet` and cannot be used for ordering if ambiguous. Use a different set without this restriction.")]
|
||||
#[display("Tried to order against `{_0}` in a schedule that has more than one `{_0}` instance. `{_0}` is a `SystemTypeSet` and cannot be used for ordering if ambiguous. Use a different set without this restriction.")]
|
||||
SystemTypeSetAmbiguity(String),
|
||||
/// Systems with conflicting access have indeterminate run order.
|
||||
///
|
||||
|
|
|
@ -161,6 +161,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline {
|
|||
},
|
||||
label: Some("LineGizmo Pipeline 2D".into()),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +262,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline {
|
|||
},
|
||||
label: Some("LineJointGizmo Pipeline 2D".into()),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline {
|
|||
},
|
||||
label: Some("LineGizmo Pipeline".into()),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,6 +257,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline {
|
|||
},
|
||||
label: Some("LineJointGizmo Pipeline".into()),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ pub(crate) enum ConvertAttributeError {
|
|||
"Vertex attribute {_0} has format {_1:?} but expected {_3:?} for target attribute {_2}"
|
||||
)]
|
||||
WrongFormat(String, VertexFormat, String, VertexFormat),
|
||||
#[display("{0} in accessor {_1}")]
|
||||
#[display("{_0} in accessor {_1}")]
|
||||
AccessFailed(AccessFailed, usize),
|
||||
#[display("Unknown vertex attribute {_0}")]
|
||||
UnknownName(String),
|
||||
|
|
0
crates/bevy_hierarchy/src/lib.rs
Executable file → Normal file
0
crates/bevy_hierarchy/src/lib.rs
Executable file → Normal file
|
@ -1,3 +1,5 @@
|
|||
//! [DirectDraw Surface](https://en.wikipedia.org/wiki/DirectDraw_Surface) functionality.
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use bevy_utils::warn_once;
|
||||
use ddsfile::{Caps2, D3DFormat, Dds, DxgiFormat};
|
||||
|
@ -16,7 +18,8 @@ pub fn dds_buffer_to_image(
|
|||
is_srgb: bool,
|
||||
) -> Result<Image, TextureError> {
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let dds = Dds::read(&mut cursor).expect("Failed to parse DDS file");
|
||||
let dds = Dds::read(&mut cursor)
|
||||
.map_err(|error| TextureError::InvalidData(format!("Failed to parse DDS file: {error}")))?;
|
||||
let texture_format = dds_format_to_texture_format(&dds, is_srgb)?;
|
||||
if !supported_compressed_formats.supports(texture_format) {
|
||||
return Err(TextureError::UnsupportedTextureFormat(format!(
|
||||
|
|
|
@ -390,6 +390,7 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
|
|||
}),
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,6 +200,7 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass<M: Material>(
|
|||
entry_point: material_fragment.entry_point,
|
||||
targets: material_fragment.targets,
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
};
|
||||
|
||||
let material_id = instance_manager.get_material_id(material_id.untyped());
|
||||
|
@ -353,6 +354,7 @@ pub fn prepare_material_meshlet_meshes_prepass<M: Material>(
|
|||
entry_point,
|
||||
targets: material_fragment.targets,
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
};
|
||||
|
||||
let material_id = instance_manager.get_material_id(material_id.untyped());
|
||||
|
|
|
@ -76,6 +76,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_FILL_CLUSTER_BUFFERS_SHADER_HANDLE,
|
||||
shader_defs: vec!["MESHLET_FILL_CLUSTER_BUFFERS_PASS".into()],
|
||||
entry_point: "fill_cluster_buffers".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -92,6 +93,7 @@ impl FromWorld for MeshletPipelines {
|
|||
"MESHLET_FIRST_CULLING_PASS".into(),
|
||||
],
|
||||
entry_point: "cull_clusters".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}),
|
||||
|
||||
cull_second: pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
|
||||
|
@ -107,6 +109,7 @@ impl FromWorld for MeshletPipelines {
|
|||
"MESHLET_SECOND_CULLING_PASS".into(),
|
||||
],
|
||||
entry_point: "cull_clusters".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}),
|
||||
|
||||
downsample_depth_first: pipeline_cache.queue_compute_pipeline(
|
||||
|
@ -120,6 +123,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_DOWNSAMPLE_DEPTH_SHADER_HANDLE,
|
||||
shader_defs: vec!["MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT".into()],
|
||||
entry_point: "downsample_depth_first".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -134,6 +138,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_DOWNSAMPLE_DEPTH_SHADER_HANDLE,
|
||||
shader_defs: vec!["MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT".into()],
|
||||
entry_point: "downsample_depth_second".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -148,6 +153,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_DOWNSAMPLE_DEPTH_SHADER_HANDLE,
|
||||
shader_defs: vec![],
|
||||
entry_point: "downsample_depth_first".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -162,6 +168,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_DOWNSAMPLE_DEPTH_SHADER_HANDLE,
|
||||
shader_defs: vec![],
|
||||
entry_point: "downsample_depth_second".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -182,6 +189,7 @@ impl FromWorld for MeshletPipelines {
|
|||
.into(),
|
||||
],
|
||||
entry_point: "rasterize_cluster".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -203,6 +211,7 @@ impl FromWorld for MeshletPipelines {
|
|||
.into(),
|
||||
],
|
||||
entry_point: "rasterize_cluster".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -226,6 +235,7 @@ impl FromWorld for MeshletPipelines {
|
|||
.into(),
|
||||
],
|
||||
entry_point: "rasterize_cluster".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}),
|
||||
|
||||
visibility_buffer_hardware_raster: pipeline_cache.queue_render_pipeline(
|
||||
|
@ -269,6 +279,7 @@ impl FromWorld for MeshletPipelines {
|
|||
write_mask: ColorWrites::empty(),
|
||||
})],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -309,6 +320,7 @@ impl FromWorld for MeshletPipelines {
|
|||
write_mask: ColorWrites::empty(),
|
||||
})],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -356,6 +368,7 @@ impl FromWorld for MeshletPipelines {
|
|||
write_mask: ColorWrites::empty(),
|
||||
})],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}),
|
||||
|
||||
resolve_depth: pipeline_cache.queue_render_pipeline(RenderPipelineDescriptor {
|
||||
|
@ -381,6 +394,7 @@ impl FromWorld for MeshletPipelines {
|
|||
entry_point: "resolve_depth".into(),
|
||||
targets: vec![],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}),
|
||||
|
||||
resolve_depth_shadow_view: pipeline_cache.queue_render_pipeline(
|
||||
|
@ -407,6 +421,7 @@ impl FromWorld for MeshletPipelines {
|
|||
entry_point: "resolve_depth".into(),
|
||||
targets: vec![],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -434,6 +449,7 @@ impl FromWorld for MeshletPipelines {
|
|||
entry_point: "resolve_material_depth".into(),
|
||||
targets: vec![],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
},
|
||||
),
|
||||
|
||||
|
@ -448,6 +464,7 @@ impl FromWorld for MeshletPipelines {
|
|||
shader: MESHLET_REMAP_1D_TO_2D_DISPATCH_SHADER_HANDLE,
|
||||
shader_defs: vec![],
|
||||
entry_point: "remap_dispatch".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
})
|
||||
}),
|
||||
}
|
||||
|
|
|
@ -571,6 +571,7 @@ where
|
|||
},
|
||||
push_constant_ranges: vec![],
|
||||
label: Some("prepass_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
};
|
||||
|
||||
// This is a bit risky because it's possible to change something that would
|
||||
|
|
|
@ -290,6 +290,7 @@ impl SpecializedComputePipeline for PreprocessPipeline {
|
|||
shader: MESH_PREPROCESS_SHADER_HANDLE,
|
||||
shader_defs,
|
||||
entry_point: "main".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2020,6 +2020,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
|
|||
alpha_to_coverage_enabled,
|
||||
},
|
||||
label: Some(label),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -448,6 +448,7 @@ impl FromWorld for SsaoPipelines {
|
|||
shader: PREPROCESS_DEPTH_SHADER_HANDLE,
|
||||
shader_defs: Vec::new(),
|
||||
entry_point: "preprocess_depth".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
|
||||
let spatial_denoise_pipeline =
|
||||
|
@ -461,6 +462,7 @@ impl FromWorld for SsaoPipelines {
|
|||
shader: SPATIAL_DENOISE_SHADER_HANDLE,
|
||||
shader_defs: Vec::new(),
|
||||
entry_point: "spatial_denoise".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
|
||||
Self {
|
||||
|
@ -513,6 +515,7 @@ impl SpecializedComputePipeline for SsaoPipelines {
|
|||
shader: SSAO_SHADER_HANDLE,
|
||||
shader_defs,
|
||||
entry_point: "ssao".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -560,6 +560,7 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline {
|
|||
primitive: default(),
|
||||
depth_stencil: None,
|
||||
multisample: default(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -600,6 +600,7 @@ impl SpecializedRenderPipeline for VolumetricFogPipeline {
|
|||
write_mask: ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
//! ## Expressive Events
|
||||
//!
|
||||
//! The events in this module (see [`events`]) cannot be listened to with normal `EventReader`s.
|
||||
//! Instead, they are dispatched to *ovservers* attached to specific entities. When events are generated, they
|
||||
//! bubble up the entity hierarchy starting from their target, until they reach the root or bubbling is haulted
|
||||
//! Instead, they are dispatched to *observers* attached to specific entities. When events are generated, they
|
||||
//! bubble up the entity hierarchy starting from their target, until they reach the root or bubbling is halted
|
||||
//! with a call to [`Trigger::propagate`](bevy_ecs::observer::Trigger::propagate).
|
||||
//! See [`Observer`] for details.
|
||||
//!
|
||||
|
@ -73,8 +73,8 @@
|
|||
//!
|
||||
//! #### Input Agnostic
|
||||
//!
|
||||
//! Picking provides a generic Pointer abstracton, which is useful for reacting to many different
|
||||
//! types of input devices. Pointers can be controlled with anything, whether its the included mouse
|
||||
//! Picking provides a generic Pointer abstraction, which is useful for reacting to many different
|
||||
//! types of input devices. Pointers can be controlled with anything, whether it's the included mouse
|
||||
//! or touch inputs, or a custom gamepad input system you write yourself to control a virtual pointer.
|
||||
//!
|
||||
//! ## Robustness
|
||||
|
|
|
@ -108,6 +108,9 @@ pub struct RenderPipelineDescriptor {
|
|||
pub multisample: MultisampleState,
|
||||
/// The compiled fragment stage, its entry point, and the color targets.
|
||||
pub fragment: Option<FragmentState>,
|
||||
/// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true.
|
||||
/// If this is false, reading from workgroup variables before writing to them will result in garbage values.
|
||||
pub zero_initialize_workgroup_memory: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
@ -147,4 +150,7 @@ pub struct ComputePipelineDescriptor {
|
|||
/// The name of the entry point in the compiled shader. There must be a
|
||||
/// function with this name in the shader.
|
||||
pub entry_point: Cow<'static, str>,
|
||||
/// Whether to zero-initialize workgroup memory by default. If you're not sure, set this to true.
|
||||
/// If this is false, reading from workgroup variables before writing to them will result in garbage values.
|
||||
pub zero_initialize_workgroup_memory: bool,
|
||||
}
|
||||
|
|
|
@ -669,6 +669,7 @@ impl PipelineCache {
|
|||
let device = self.device.clone();
|
||||
let shader_cache = self.shader_cache.clone();
|
||||
let layout_cache = self.layout_cache.clone();
|
||||
|
||||
create_pipeline_task(
|
||||
async move {
|
||||
let mut shader_cache = shader_cache.lock().unwrap();
|
||||
|
@ -731,10 +732,10 @@ impl PipelineCache {
|
|||
)
|
||||
});
|
||||
|
||||
// TODO: Expose this somehow
|
||||
// TODO: Expose the rest of this somehow
|
||||
let compilation_options = PipelineCompilationOptions {
|
||||
constants: &std::collections::HashMap::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
constants: &default(),
|
||||
zero_initialize_workgroup_memory: descriptor.zero_initialize_workgroup_memory,
|
||||
};
|
||||
|
||||
let descriptor = RawRenderPipelineDescriptor {
|
||||
|
@ -779,6 +780,7 @@ impl PipelineCache {
|
|||
let device = self.device.clone();
|
||||
let shader_cache = self.shader_cache.clone();
|
||||
let layout_cache = self.layout_cache.clone();
|
||||
|
||||
create_pipeline_task(
|
||||
async move {
|
||||
let mut shader_cache = shader_cache.lock().unwrap();
|
||||
|
@ -812,10 +814,11 @@ impl PipelineCache {
|
|||
layout: layout.as_ref().map(|layout| -> &PipelineLayout { layout }),
|
||||
module: &compute_module,
|
||||
entry_point: Some(&descriptor.entry_point),
|
||||
// TODO: Expose this somehow
|
||||
// TODO: Expose the rest of this somehow
|
||||
compilation_options: PipelineCompilationOptions {
|
||||
constants: &std::collections::HashMap::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
constants: &default(),
|
||||
zero_initialize_workgroup_memory: descriptor
|
||||
.zero_initialize_workgroup_memory,
|
||||
},
|
||||
cache: None,
|
||||
};
|
||||
|
|
|
@ -496,6 +496,7 @@ impl SpecializedRenderPipeline for ScreenshotToScreenPipeline {
|
|||
})],
|
||||
}),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -674,6 +674,7 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some(label.into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -323,6 +323,7 @@ impl SpecializedRenderPipeline for SpritePipeline {
|
|||
},
|
||||
label: Some("sprite_pipeline".into()),
|
||||
push_constant_ranges: Vec::new(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,8 @@ impl Plugin for TextPlugin {
|
|||
.register_type::<TextColor>()
|
||||
.register_type::<TextSpan>()
|
||||
.register_type::<TextBounds>()
|
||||
.register_type::<TextLayout>()
|
||||
.register_type::<ComputedTextBlock>()
|
||||
.init_asset_loader::<FontLoader>()
|
||||
.init_resource::<FontAtlasSets>()
|
||||
.init_resource::<TextPipeline>()
|
||||
|
|
|
@ -28,7 +28,8 @@ impl Default for CosmicBuffer {
|
|||
/// A sub-entity of a [`ComputedTextBlock`].
|
||||
///
|
||||
/// Returned by [`ComputedTextBlock::entities`].
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, Reflect)]
|
||||
#[reflect(Debug)]
|
||||
pub struct TextEntity {
|
||||
/// The entity.
|
||||
pub entity: Entity,
|
||||
|
@ -41,7 +42,8 @@ pub struct TextEntity {
|
|||
/// See [`TextLayout`].
|
||||
///
|
||||
/// Automatically updated by 2d and UI text systems.
|
||||
#[derive(Component, Debug, Clone)]
|
||||
#[derive(Component, Debug, Clone, Reflect)]
|
||||
#[reflect(Component, Debug, Default)]
|
||||
pub struct ComputedTextBlock {
|
||||
/// Buffer for managing text layout and creating [`TextLayoutInfo`].
|
||||
///
|
||||
|
@ -49,6 +51,7 @@ pub struct ComputedTextBlock {
|
|||
/// `TextLayoutInfo`. If you want to control the buffer contents manually or use the `cosmic-text`
|
||||
/// editor, then you need to not use `TextLayout` and instead manually implement the conversion to
|
||||
/// `TextLayoutInfo`.
|
||||
#[reflect(ignore)]
|
||||
pub(crate) buffer: CosmicBuffer,
|
||||
/// Entities for all text spans in the block, including the root-level text.
|
||||
///
|
||||
|
|
|
@ -43,6 +43,7 @@ derive_more = { version = "1", default-features = false, features = [
|
|||
] }
|
||||
nonmax = "0.5"
|
||||
smallvec = "1.11"
|
||||
accesskit = "0.17"
|
||||
|
||||
[features]
|
||||
default = ["bevy_ui_picking_backend"]
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use crate::{
|
||||
experimental::UiChildren,
|
||||
prelude::{Button, Label},
|
||||
widget::{TextUiReader, UiImage},
|
||||
widget::{ImageNode, TextUiReader},
|
||||
ComputedNode,
|
||||
};
|
||||
use bevy_a11y::{
|
||||
accesskit::{Node, Rect, Role},
|
||||
AccessibilityNode,
|
||||
};
|
||||
use bevy_a11y::AccessibilityNode;
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_ecs::{
|
||||
prelude::{DetectChanges, Entity},
|
||||
|
@ -19,6 +16,8 @@ use bevy_ecs::{
|
|||
use bevy_render::{camera::CameraUpdateSystem, prelude::Camera};
|
||||
use bevy_transform::prelude::GlobalTransform;
|
||||
|
||||
use accesskit::{Node, Rect, Role};
|
||||
|
||||
fn calc_label(
|
||||
text_reader: &mut TextUiReader,
|
||||
children: impl Iterator<Item = Entity>,
|
||||
|
@ -92,7 +91,10 @@ fn button_changed(
|
|||
|
||||
fn image_changed(
|
||||
mut commands: Commands,
|
||||
mut query: Query<(Entity, Option<&mut AccessibilityNode>), (Changed<UiImage>, Without<Button>)>,
|
||||
mut query: Query<
|
||||
(Entity, Option<&mut AccessibilityNode>),
|
||||
(Changed<ImageNode>, Without<Button>),
|
||||
>,
|
||||
ui_children: UiChildren,
|
||||
mut text_reader: TextUiReader,
|
||||
) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
|
||||
//! # Basic usage
|
||||
//! Spawn UI elements with [`widget::Button`], [`UiImage`], [`Text`](prelude::Text) and [`Node`]
|
||||
//! Spawn UI elements with [`widget::Button`], [`ImageNode`], [`Text`](prelude::Text) and [`Node`]
|
||||
//! This UI is laid out with the Flexbox and CSS Grid layout models (see <https://cssreference.io/flexbox/>)
|
||||
|
||||
pub mod measurement;
|
||||
|
@ -40,7 +40,7 @@ pub use measurement::*;
|
|||
pub use render::*;
|
||||
pub use ui_material::*;
|
||||
pub use ui_node::*;
|
||||
use widget::{UiImage, UiImageSize};
|
||||
use widget::{ImageNode, ImageNodeSize};
|
||||
|
||||
/// The UI prelude.
|
||||
///
|
||||
|
@ -58,7 +58,7 @@ pub mod prelude {
|
|||
node_bundles::*,
|
||||
ui_material::*,
|
||||
ui_node::*,
|
||||
widget::{Button, Label, UiImage},
|
||||
widget::{Button, ImageNode, Label},
|
||||
Interaction, MaterialNode, UiMaterialPlugin, UiScale,
|
||||
},
|
||||
// `bevy_sprite` re-exports for texture slicing
|
||||
|
@ -155,8 +155,8 @@ impl Plugin for UiPlugin {
|
|||
.register_type::<RelativeCursorPosition>()
|
||||
.register_type::<ScrollPosition>()
|
||||
.register_type::<TargetCamera>()
|
||||
.register_type::<UiImage>()
|
||||
.register_type::<UiImageSize>()
|
||||
.register_type::<ImageNode>()
|
||||
.register_type::<ImageNodeSize>()
|
||||
.register_type::<UiRect>()
|
||||
.register_type::<UiScale>()
|
||||
.register_type::<BorderColor>()
|
||||
|
@ -208,7 +208,7 @@ impl Plugin for UiPlugin {
|
|||
update_clipping_system.after(TransformSystem::TransformPropagate),
|
||||
// Potential conflicts: `Assets<Image>`
|
||||
// They run independently since `widget::image_node_system` will only ever observe
|
||||
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
|
||||
// its own ImageNode, and `widget::text_system` & `bevy_text::update_text2d_layout`
|
||||
// will never modify a pre-existing `Image` asset.
|
||||
widget::update_image_content_size_system
|
||||
.in_set(UiSystem::Prepare)
|
||||
|
@ -265,7 +265,7 @@ fn build_text_interop(app: &mut App) {
|
|||
// Since both systems will only ever insert new [`Image`] assets,
|
||||
// they will never observe each other's effects.
|
||||
.ambiguous_with(bevy_text::update_text2d_layout)
|
||||
// We assume Text is on disjoint UI entities to UiImage and UiTextureAtlasImage
|
||||
// We assume Text is on disjoint UI entities to ImageNode and UiTextureAtlasImage
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(widget::update_image_content_size_system),
|
||||
widget::text_system
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#![expect(deprecated)]
|
||||
|
||||
use crate::{
|
||||
widget::{Button, UiImageSize},
|
||||
BackgroundColor, BorderColor, BorderRadius, ComputedNode, ContentSize, FocusPolicy,
|
||||
Interaction, MaterialNode, Node, ScrollPosition, UiImage, UiMaterial, ZIndex,
|
||||
widget::{Button, ImageNodeSize},
|
||||
BackgroundColor, BorderColor, BorderRadius, ComputedNode, ContentSize, FocusPolicy, ImageNode,
|
||||
Interaction, MaterialNode, Node, ScrollPosition, UiMaterial, ZIndex,
|
||||
};
|
||||
use bevy_ecs::bundle::Bundle;
|
||||
use bevy_render::view::{InheritedVisibility, ViewVisibility, Visibility};
|
||||
|
@ -60,7 +60,7 @@ pub struct NodeBundle {
|
|||
#[derive(Bundle, Debug, Default)]
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `UiImage` component instead. Inserting `UiImage` will also insert the other components required automatically."
|
||||
note = "Use the `ImageNode` component instead. Inserting `ImageNode` will also insert the other components required automatically."
|
||||
)]
|
||||
pub struct ImageBundle {
|
||||
/// Describes the logical size of the node
|
||||
|
@ -73,7 +73,7 @@ pub struct ImageBundle {
|
|||
/// The image of the node.
|
||||
///
|
||||
/// To tint the image, change the `color` field of this component.
|
||||
pub image: UiImage,
|
||||
pub image: ImageNode,
|
||||
/// The color of the background that will fill the containing node.
|
||||
pub background_color: BackgroundColor,
|
||||
/// The border radius of the node
|
||||
|
@ -81,7 +81,7 @@ pub struct ImageBundle {
|
|||
/// The size of the image in pixels
|
||||
///
|
||||
/// This component is set automatically
|
||||
pub image_size: UiImageSize,
|
||||
pub image_size: ImageNodeSize,
|
||||
/// Whether this node should block interaction with lower nodes
|
||||
pub focus_policy: FocusPolicy,
|
||||
/// The transform of the node
|
||||
|
@ -126,7 +126,7 @@ pub struct ButtonBundle {
|
|||
/// The border radius of the node
|
||||
pub border_radius: BorderRadius,
|
||||
/// The image of the node
|
||||
pub image: UiImage,
|
||||
pub image: ImageNode,
|
||||
/// The background color that will fill the containing node
|
||||
pub background_color: BackgroundColor,
|
||||
/// The transform of the node
|
||||
|
|
|
@ -206,6 +206,7 @@ impl SpecializedRenderPipeline for BoxShadowPipeline {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some("box_shadow_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ mod render_pass;
|
|||
mod ui_material_pipeline;
|
||||
pub mod ui_texture_slice_pipeline;
|
||||
|
||||
use crate::widget::UiImage;
|
||||
use crate::widget::ImageNode;
|
||||
use crate::{
|
||||
experimental::UiChildren, BackgroundColor, BorderColor, CalculatedClip, ComputedNode,
|
||||
DefaultUiCamera, Outline, ResolvedBorderRadius, TargetCamera, UiAntiAlias, UiBoxShadowSamples,
|
||||
|
@ -110,7 +110,7 @@ pub fn build_ui_render(app: &mut App) {
|
|||
|
||||
render_app
|
||||
.init_resource::<SpecializedRenderPipelines<UiPipeline>>()
|
||||
.init_resource::<UiImageBindGroups>()
|
||||
.init_resource::<ImageNodeBindGroups>()
|
||||
.init_resource::<UiMeta>()
|
||||
.init_resource::<ExtractedUiNodes>()
|
||||
.allow_ambiguous_resource::<ExtractedUiNodes>()
|
||||
|
@ -318,7 +318,7 @@ pub fn extract_uinode_images(
|
|||
&ViewVisibility,
|
||||
Option<&CalculatedClip>,
|
||||
Option<&TargetCamera>,
|
||||
&UiImage,
|
||||
&ImageNode,
|
||||
)>,
|
||||
>,
|
||||
mapping: Extract<Query<RenderEntity>>,
|
||||
|
@ -874,7 +874,7 @@ pub fn queue_uinodes(
|
|||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct UiImageBindGroups {
|
||||
pub struct ImageNodeBindGroups {
|
||||
pub values: HashMap<AssetId<Image>, BindGroup>,
|
||||
}
|
||||
|
||||
|
@ -887,7 +887,7 @@ pub fn prepare_uinodes(
|
|||
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
|
||||
view_uniforms: Res<ViewUniforms>,
|
||||
ui_pipeline: Res<UiPipeline>,
|
||||
mut image_bind_groups: ResMut<UiImageBindGroups>,
|
||||
mut image_bind_groups: ResMut<ImageNodeBindGroups>,
|
||||
gpu_images: Res<RenderAssets<GpuImage>>,
|
||||
mut phases: ResMut<ViewSortedRenderPhases<TransparentUi>>,
|
||||
events: Res<SpriteAssetEvents>,
|
||||
|
|
|
@ -121,6 +121,7 @@ impl SpecializedRenderPipeline for UiPipeline {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some("ui_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::ops::Range;
|
||||
|
||||
use super::{UiBatch, UiImageBindGroups, UiMeta};
|
||||
use super::{ImageNodeBindGroups, UiBatch, UiMeta};
|
||||
use crate::DefaultCameraView;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
|
@ -185,7 +185,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiViewBindGroup<I> {
|
|||
}
|
||||
pub struct SetUiTextureBindGroup<const I: usize>;
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetUiTextureBindGroup<I> {
|
||||
type Param = SRes<UiImageBindGroups>;
|
||||
type Param = SRes<ImageNodeBindGroups>;
|
||||
type ViewQuery = ();
|
||||
type ItemQuery = Read<UiBatch>;
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ where
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some("ui_material_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
};
|
||||
if let Some(vertex_shader) = &self.vertex_shader {
|
||||
descriptor.vertex.shader = vertex_shader.clone();
|
||||
|
|
|
@ -30,7 +30,7 @@ use bevy_transform::prelude::GlobalTransform;
|
|||
use bevy_utils::HashMap;
|
||||
use binding_types::{sampler, texture_2d};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use widget::UiImage;
|
||||
use widget::ImageNode;
|
||||
|
||||
pub const UI_SLICER_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(11156288772117983964);
|
||||
|
||||
|
@ -219,6 +219,7 @@ impl SpecializedRenderPipeline for UiTextureSlicePipeline {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some("ui_texture_slice_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +257,7 @@ pub fn extract_ui_texture_slices(
|
|||
&ViewVisibility,
|
||||
Option<&CalculatedClip>,
|
||||
Option<&TargetCamera>,
|
||||
&UiImage,
|
||||
&ImageNode,
|
||||
)>,
|
||||
>,
|
||||
mapping: Extract<Query<RenderEntity>>,
|
||||
|
|
|
@ -9,11 +9,11 @@ use bevy_sprite::{TextureAtlas, TextureAtlasLayout, TextureSlicer};
|
|||
use bevy_window::{PrimaryWindow, Window};
|
||||
use taffy::{MaybeMath, MaybeResolve};
|
||||
|
||||
/// The 2D texture displayed for this UI node
|
||||
/// A UI Node that renders an image.
|
||||
#[derive(Component, Clone, Debug, Reflect)]
|
||||
#[reflect(Component, Default, Debug)]
|
||||
#[require(Node, UiImageSize, ContentSize)]
|
||||
pub struct UiImage {
|
||||
#[require(Node, ImageNodeSize, ContentSize)]
|
||||
pub struct ImageNode {
|
||||
/// The tint color used to draw the image.
|
||||
///
|
||||
/// This is multiplied by the color of each pixel in the image.
|
||||
|
@ -39,16 +39,16 @@ pub struct UiImage {
|
|||
pub image_mode: NodeImageMode,
|
||||
}
|
||||
|
||||
impl Default for UiImage {
|
||||
impl Default for ImageNode {
|
||||
/// A transparent 1x1 image with a solid white tint.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This will be invisible by default.
|
||||
/// To set this to a visible image, you need to set the `texture` field to a valid image handle,
|
||||
/// or use [`Handle<Image>`]'s default 1x1 solid white texture (as is done in [`UiImage::solid_color`]).
|
||||
/// or use [`Handle<Image>`]'s default 1x1 solid white texture (as is done in [`ImageNode::solid_color`]).
|
||||
fn default() -> Self {
|
||||
UiImage {
|
||||
ImageNode {
|
||||
// This should be white because the tint is multiplied with the image,
|
||||
// so if you set an actual image with default tint you'd want its original colors
|
||||
color: Color::WHITE,
|
||||
|
@ -63,8 +63,8 @@ impl Default for UiImage {
|
|||
}
|
||||
}
|
||||
|
||||
impl UiImage {
|
||||
/// Create a new [`UiImage`] with the given texture.
|
||||
impl ImageNode {
|
||||
/// Create a new [`ImageNode`] with the given texture.
|
||||
pub fn new(texture: Handle<Image>) -> Self {
|
||||
Self {
|
||||
image: texture,
|
||||
|
@ -73,7 +73,7 @@ impl UiImage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a solid color [`UiImage`].
|
||||
/// Create a solid color [`ImageNode`].
|
||||
///
|
||||
/// This is primarily useful for debugging / mocking the extents of your image.
|
||||
pub fn solid_color(color: Color) -> Self {
|
||||
|
@ -88,7 +88,7 @@ impl UiImage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a [`UiImage`] from an image, with an associated texture atlas
|
||||
/// Create a [`ImageNode`] from an image, with an associated texture atlas
|
||||
pub fn from_atlas_image(image: Handle<Image>, atlas: TextureAtlas) -> Self {
|
||||
Self {
|
||||
image,
|
||||
|
@ -131,7 +131,7 @@ impl UiImage {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Handle<Image>> for UiImage {
|
||||
impl From<Handle<Image>> for ImageNode {
|
||||
fn from(texture: Handle<Image>) -> Self {
|
||||
Self::new(texture)
|
||||
}
|
||||
|
@ -175,14 +175,14 @@ impl NodeImageMode {
|
|||
/// This component is updated automatically by [`update_image_content_size_system`]
|
||||
#[derive(Component, Debug, Copy, Clone, Default, Reflect)]
|
||||
#[reflect(Component, Default, Debug)]
|
||||
pub struct UiImageSize {
|
||||
pub struct ImageNodeSize {
|
||||
/// The size of the image's texture
|
||||
///
|
||||
/// This field is updated automatically by [`update_image_content_size_system`]
|
||||
size: UVec2,
|
||||
}
|
||||
|
||||
impl UiImageSize {
|
||||
impl ImageNodeSize {
|
||||
/// The size of the image's texture
|
||||
pub fn size(&self) -> UVec2 {
|
||||
self.size
|
||||
|
@ -259,7 +259,7 @@ pub fn update_image_content_size_system(
|
|||
textures: Res<Assets<Image>>,
|
||||
|
||||
atlases: Res<Assets<TextureAtlasLayout>>,
|
||||
mut query: Query<(&mut ContentSize, Ref<UiImage>, &mut UiImageSize), UpdateImageFilter>,
|
||||
mut query: Query<(&mut ContentSize, Ref<ImageNode>, &mut ImageNodeSize), UpdateImageFilter>,
|
||||
) {
|
||||
let combined_scale_factor = windows
|
||||
.get_single()
|
||||
|
|
|
@ -52,6 +52,7 @@ raw-window-handle = "0.6"
|
|||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
bytemuck = { version = "1.5", optional = true }
|
||||
wgpu-types = { version = "23", optional = true }
|
||||
accesskit = "0.17"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use accesskit::{
|
||||
ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, Node, NodeId, Role, Tree,
|
||||
TreeUpdate,
|
||||
};
|
||||
use accesskit_winit::Adapter;
|
||||
use bevy_a11y::{
|
||||
accesskit::{
|
||||
ActionHandler, ActionRequest, ActivationHandler, DeactivationHandler, Node, NodeId, Role,
|
||||
Tree, TreeUpdate,
|
||||
},
|
||||
AccessibilityNode, AccessibilityRequested, AccessibilitySystem,
|
||||
ActionRequest as ActionRequestWrapper, Focus, ManageAccessibilityUpdates,
|
||||
};
|
||||
|
|
|
@ -385,8 +385,11 @@ pub(crate) fn changed_windows(
|
|||
}
|
||||
}
|
||||
|
||||
if window.cursor_options.grab_mode != cache.window.cursor_options.grab_mode {
|
||||
crate::winit_windows::attempt_grab(winit_window, window.cursor_options.grab_mode);
|
||||
if window.cursor_options.grab_mode != cache.window.cursor_options.grab_mode
|
||||
&& crate::winit_windows::attempt_grab(winit_window, window.cursor_options.grab_mode)
|
||||
.is_err()
|
||||
{
|
||||
window.cursor_options.grab_mode = cache.window.cursor_options.grab_mode;
|
||||
}
|
||||
|
||||
if window.cursor_options.visible != cache.window.cursor_options.visible {
|
||||
|
|
|
@ -10,6 +10,7 @@ use bevy_window::{
|
|||
|
||||
use winit::{
|
||||
dpi::{LogicalSize, PhysicalPosition},
|
||||
error::ExternalError,
|
||||
event_loop::ActiveEventLoop,
|
||||
monitor::{MonitorHandle, VideoModeHandle},
|
||||
window::{CursorGrabMode as WinitCursorGrabMode, Fullscreen, Window as WinitWindow, WindowId},
|
||||
|
@ -279,7 +280,7 @@ impl WinitWindows {
|
|||
|
||||
// Do not set the grab mode on window creation if it's none. It can fail on mobile.
|
||||
if window.cursor_options.grab_mode != CursorGrabMode::None {
|
||||
attempt_grab(&winit_window, window.cursor_options.grab_mode);
|
||||
let _ = attempt_grab(&winit_window, window.cursor_options.grab_mode);
|
||||
}
|
||||
|
||||
winit_window.set_cursor_visible(window.cursor_options.visible);
|
||||
|
@ -380,7 +381,10 @@ pub fn get_best_videomode(monitor: &MonitorHandle) -> VideoModeHandle {
|
|||
modes.first().unwrap().clone()
|
||||
}
|
||||
|
||||
pub(crate) fn attempt_grab(winit_window: &WinitWindow, grab_mode: CursorGrabMode) {
|
||||
pub(crate) fn attempt_grab(
|
||||
winit_window: &WinitWindow,
|
||||
grab_mode: CursorGrabMode,
|
||||
) -> Result<(), ExternalError> {
|
||||
let grab_result = match grab_mode {
|
||||
CursorGrabMode::None => winit_window.set_cursor_grab(WinitCursorGrabMode::None),
|
||||
CursorGrabMode::Confined => winit_window
|
||||
|
@ -398,6 +402,9 @@ pub(crate) fn attempt_grab(winit_window: &WinitWindow, grab_mode: CursorGrabMode
|
|||
};
|
||||
|
||||
bevy_utils::tracing::error!("Unable to {} cursor: {}", err_desc, err);
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -220,6 +220,7 @@ impl SpecializedRenderPipeline for ColoredMesh2dPipeline {
|
|||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
label: Some("colored_mesh2d_pipeline".into()),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ fn setup(
|
|||
));
|
||||
|
||||
commands.spawn((
|
||||
UiImage {
|
||||
ImageNode {
|
||||
image: metering_mask,
|
||||
..default()
|
||||
},
|
||||
|
@ -162,7 +162,7 @@ struct ExampleResources {
|
|||
fn example_control_system(
|
||||
camera: Single<(&mut Transform, &mut AutoExposure), With<Camera3d>>,
|
||||
mut display: Single<&mut Text, With<ExampleDisplay>>,
|
||||
mut mask_image: Single<&mut Node, With<UiImage>>,
|
||||
mut mask_image: Single<&mut Node, With<ImageNode>>,
|
||||
time: Res<Time>,
|
||||
input: Res<ButtonInput<KeyCode>>,
|
||||
resources: Res<ExampleResources>,
|
||||
|
|
|
@ -516,7 +516,6 @@ Example | Description
|
|||
[Text Debug](../examples/ui/text_debug.rs) | An example for debugging text layout
|
||||
[Text Wrap Debug](../examples/ui/text_wrap_debug.rs) | Demonstrates text wrapping
|
||||
[Transparency UI](../examples/ui/transparency_ui.rs) | Demonstrates transparency for UI
|
||||
[UI](../examples/ui/ui.rs) | Illustrates various features of Bevy UI
|
||||
[UI Material](../examples/ui/ui_material.rs) | Demonstrates creating and using custom Ui materials
|
||||
[UI Scaling](../examples/ui/ui_scaling.rs) | Illustrates how to scale the UI
|
||||
[UI Texture Atlas](../examples/ui/ui_texture_atlas.rs) | Illustrates how to use TextureAtlases in UI
|
||||
|
|
|
@ -361,7 +361,7 @@ fn setup_animation_graph_once_loaded(
|
|||
.from_asset("models/animated/Fox.glb"),
|
||||
);
|
||||
let mask = if animation_index == 0 { 0 } else { 0x3f };
|
||||
animation_graph.add_clip_with_mask(handle, mask, 0.0, blend_node)
|
||||
animation_graph.add_clip_with_mask(handle, mask, 1.0, blend_node)
|
||||
});
|
||||
|
||||
// Create each mask group.
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
}
|
||||
|
||||
fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
commands.spawn(AudioPlayer::<AudioSource>(
|
||||
commands.spawn(AudioPlayer::new(
|
||||
asset_server.load("sounds/Windless Slopes.ogg"),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn((
|
||||
AudioPlayer::<AudioSource>(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
MyMusic,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ fn setup(
|
|||
MeshMaterial2d(materials.add(Color::from(BLUE))),
|
||||
Transform::from_translation(Vec3::new(0.0, 50.0, 0.0)),
|
||||
Emitter::default(),
|
||||
AudioPlayer::<AudioSource>(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
PlaybackSettings::LOOP.with_spatial(true),
|
||||
));
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ fn setup(
|
|||
MeshMaterial3d(materials.add(Color::from(BLUE))),
|
||||
Transform::from_xyz(0.0, 0.0, 0.0),
|
||||
Emitter::default(),
|
||||
AudioPlayer::<AudioSource>(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
PlaybackSettings::LOOP.with_spatial(true),
|
||||
));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use bevy::prelude::*;
|
|||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
|
||||
enum GameState {
|
||||
#[default]
|
||||
Playing,
|
||||
|
@ -25,6 +25,7 @@ fn main() {
|
|||
TimerMode::Repeating,
|
||||
)))
|
||||
.init_state::<GameState>()
|
||||
.enable_state_scoped_entities::<GameState>()
|
||||
.add_systems(Startup, setup_cameras)
|
||||
.add_systems(OnEnter(GameState::Playing), setup)
|
||||
.add_systems(
|
||||
|
@ -38,13 +39,11 @@ fn main() {
|
|||
)
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
)
|
||||
.add_systems(OnExit(GameState::Playing), teardown)
|
||||
.add_systems(OnEnter(GameState::GameOver), display_score)
|
||||
.add_systems(
|
||||
Update,
|
||||
gameover_keyboard.run_if(in_state(GameState::GameOver)),
|
||||
)
|
||||
.add_systems(OnExit(GameState::GameOver), teardown)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
@ -122,6 +121,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
game.player.move_cooldown = Timer::from_seconds(0.3, TimerMode::Once);
|
||||
|
||||
commands.spawn((
|
||||
StateScoped(GameState::Playing),
|
||||
PointLight {
|
||||
intensity: 2_000_000.0,
|
||||
shadows_enabled: true,
|
||||
|
@ -140,6 +140,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
.map(|i| {
|
||||
let height = rng.gen_range(-0.1..0.1);
|
||||
commands.spawn((
|
||||
StateScoped(GameState::Playing),
|
||||
Transform::from_xyz(i as f32, height - 0.2, j as f32),
|
||||
SceneRoot(cell_scene.clone()),
|
||||
));
|
||||
|
@ -153,6 +154,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
game.player.entity = Some(
|
||||
commands
|
||||
.spawn((
|
||||
StateScoped(GameState::Playing),
|
||||
Transform {
|
||||
translation: Vec3::new(
|
||||
game.player.i as f32,
|
||||
|
@ -176,6 +178,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
|
||||
// scoreboard
|
||||
commands.spawn((
|
||||
StateScoped(GameState::Playing),
|
||||
Text::new("Score:"),
|
||||
TextFont {
|
||||
font_size: 33.0,
|
||||
|
@ -193,13 +196,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
commands.insert_resource(Random(rng));
|
||||
}
|
||||
|
||||
// remove all entities that are not a camera or window
|
||||
fn teardown(mut commands: Commands, entities: Query<Entity, (Without<Camera>, Without<Window>)>) {
|
||||
for entity in &entities {
|
||||
commands.entity(entity).despawn();
|
||||
}
|
||||
}
|
||||
|
||||
// control the game character
|
||||
fn move_player(
|
||||
mut commands: Commands,
|
||||
|
@ -344,6 +340,7 @@ fn spawn_bonus(
|
|||
game.bonus.entity = Some(
|
||||
commands
|
||||
.spawn((
|
||||
StateScoped(GameState::Playing),
|
||||
Transform::from_xyz(
|
||||
game.bonus.i as f32,
|
||||
game.board[game.bonus.j][game.bonus.i].height + 0.2,
|
||||
|
@ -393,12 +390,15 @@ fn gameover_keyboard(
|
|||
// display the number of cake eaten before losing
|
||||
fn display_score(mut commands: Commands, game: Res<Game>) {
|
||||
commands
|
||||
.spawn(Node {
|
||||
width: Val::Percent(100.),
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
..default()
|
||||
})
|
||||
.spawn((
|
||||
StateScoped(GameState::GameOver),
|
||||
Node {
|
||||
width: Val::Percent(100.),
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
..default()
|
||||
},
|
||||
))
|
||||
.with_child((
|
||||
Text::new(format!("Cake eaten: {}", game.cake_eaten)),
|
||||
TextFont {
|
||||
|
|
|
@ -86,7 +86,7 @@ mod splash {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
UiImage::new(icon),
|
||||
ImageNode::new(icon),
|
||||
Node {
|
||||
// This will set the logo to be 200px wide, and auto adjust its height
|
||||
width: Val::Px(200.0),
|
||||
|
@ -444,7 +444,7 @@ mod menu {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
let icon = asset_server.load("textures/Game Icons/right.png");
|
||||
parent.spawn((UiImage::new(icon), button_icon_node.clone()));
|
||||
parent.spawn((ImageNode::new(icon), button_icon_node.clone()));
|
||||
parent.spawn((
|
||||
Text::new("New Game"),
|
||||
button_text_font.clone(),
|
||||
|
@ -460,7 +460,7 @@ mod menu {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
let icon = asset_server.load("textures/Game Icons/wrench.png");
|
||||
parent.spawn((UiImage::new(icon), button_icon_node.clone()));
|
||||
parent.spawn((ImageNode::new(icon), button_icon_node.clone()));
|
||||
parent.spawn((
|
||||
Text::new("Settings"),
|
||||
button_text_font.clone(),
|
||||
|
@ -476,7 +476,7 @@ mod menu {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
let icon = asset_server.load("textures/Game Icons/exitRight.png");
|
||||
parent.spawn((UiImage::new(icon), button_icon_node));
|
||||
parent.spawn((ImageNode::new(icon), button_icon_node));
|
||||
parent.spawn((
|
||||
Text::new("Quit"),
|
||||
button_text_font,
|
||||
|
|
|
@ -162,7 +162,7 @@ fn button_handler(
|
|||
|
||||
fn setup_music(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
commands.spawn((
|
||||
AudioPlayer::<AudioSource>(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")),
|
||||
PlaybackSettings::LOOP,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -179,6 +179,7 @@ impl FromWorld for GameOfLifePipeline {
|
|||
shader: shader.clone(),
|
||||
shader_defs: vec![],
|
||||
entry_point: Cow::from("init"),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
let update_pipeline = pipeline_cache.queue_compute_pipeline(ComputePipelineDescriptor {
|
||||
label: None,
|
||||
|
@ -187,6 +188,7 @@ impl FromWorld for GameOfLifePipeline {
|
|||
shader,
|
||||
shader_defs: vec![],
|
||||
entry_point: Cow::from("update"),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
|
||||
GameOfLifePipeline {
|
||||
|
|
|
@ -343,6 +343,7 @@ impl SpecializedRenderPipeline for CustomPhasePipeline {
|
|||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
zero_initialize_workgroup_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,6 +287,7 @@ impl FromWorld for PostProcessPipeline {
|
|||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
push_constant_ranges: vec![],
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
|
||||
Self {
|
||||
|
|
|
@ -180,6 +180,7 @@ impl FromWorld for ComputePipeline {
|
|||
shader: shader.clone(),
|
||||
shader_defs: Vec::new(),
|
||||
entry_point: "main".into(),
|
||||
zero_initialize_workgroup_memory: false,
|
||||
});
|
||||
ComputePipeline { layout, pipeline }
|
||||
}
|
||||
|
|
|
@ -263,6 +263,7 @@ impl SpecializedMeshPipeline for CustomMeshPipeline {
|
|||
count: mesh_key.msaa_samples(),
|
||||
..MultisampleState::default()
|
||||
},
|
||||
zero_initialize_workgroup_memory: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,7 +252,7 @@ fn spawn_button(
|
|||
));
|
||||
|
||||
if let Some(image) = image {
|
||||
builder.insert(UiImage::new(image));
|
||||
builder.insert(ImageNode::new(image));
|
||||
}
|
||||
|
||||
if spawn_text {
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use accesskit::{Node as Accessible, Role};
|
||||
use bevy::{
|
||||
a11y::{
|
||||
accesskit::{Node as Accessible, Role},
|
||||
AccessibilityNode,
|
||||
},
|
||||
a11y::AccessibilityNode,
|
||||
color::palettes::{basic::LIME, css::DARK_GRAY},
|
||||
input::mouse::{MouseScrollUnit, MouseWheel},
|
||||
picking::focus::HoverMap,
|
||||
|
@ -182,7 +180,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
UiImage::new(asset_server.load("branding/bevy_logo_light.png")),
|
||||
ImageNode::new(asset_server.load("branding/bevy_logo_light.png")),
|
||||
// Uses the transform to rotate the logo image by 45 degrees
|
||||
Transform::from_rotation(Quat::from_rotation_z(0.25 * PI)),
|
||||
BorderRadius::all(Val::Px(10.)),
|
||||
|
@ -294,7 +292,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// bevy logo (image)
|
||||
parent
|
||||
.spawn((
|
||||
UiImage::new(asset_server.load("branding/bevy_logo_dark_big.png"))
|
||||
ImageNode::new(asset_server.load("branding/bevy_logo_dark_big.png"))
|
||||
.with_mode(NodeImageMode::Stretch),
|
||||
Node {
|
||||
width: Val::Px(500.0),
|
||||
|
@ -334,17 +332,17 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
[(false, false), (false, true), (true, true), (true, false)]
|
||||
{
|
||||
parent.spawn((
|
||||
Node {
|
||||
// The height will be chosen automatically to preserve the image's aspect ratio
|
||||
width: Val::Px(75.),
|
||||
..default()
|
||||
},
|
||||
UiImage {
|
||||
ImageNode {
|
||||
image: asset_server.load("branding/icon.png"),
|
||||
flip_x,
|
||||
flip_y,
|
||||
..default()
|
||||
},
|
||||
Node {
|
||||
// The height will be chosen automatically to preserve the image's aspect ratio
|
||||
width: Val::Px(75.),
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
});
|
|
@ -49,7 +49,7 @@ fn atlas_render_system(
|
|||
let font_atlas = &font_atlas[state.atlas_count as usize];
|
||||
state.atlas_count += 1;
|
||||
commands.spawn((
|
||||
UiImage::new(font_atlas.texture.clone()),
|
||||
ImageNode::new(font_atlas.texture.clone()),
|
||||
Node {
|
||||
position_type: PositionType::Absolute,
|
||||
top: Val::ZERO,
|
||||
|
|
|
@ -77,7 +77,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
UiImage::new(image.clone()),
|
||||
ImageNode::new(image.clone()),
|
||||
Node {
|
||||
min_width: Val::Px(100.),
|
||||
min_height: Val::Px(100.),
|
||||
|
|
|
@ -80,7 +80,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
BackgroundColor(LIGHT_CYAN.into()),
|
||||
))
|
||||
.with_child((
|
||||
UiImage::new(image.clone()),
|
||||
ImageNode::new(image.clone()),
|
||||
Node {
|
||||
min_width: Val::Px(100.),
|
||||
min_height: Val::Px(100.),
|
||||
|
|
|
@ -141,7 +141,7 @@ fn spawn_image(
|
|||
) {
|
||||
spawn_container(parent, update_transform, |parent| {
|
||||
parent.spawn((
|
||||
UiImage::new(asset_server.load("branding/bevy_logo_dark_big.png")),
|
||||
ImageNode::new(asset_server.load("branding/bevy_logo_dark_big.png")),
|
||||
Node {
|
||||
height: Val::Px(100.),
|
||||
position_type: PositionType::Absolute,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
//! This example illustrates scrolling in Bevy UI.
|
||||
|
||||
use accesskit::{Node as Accessible, Role};
|
||||
use bevy::{
|
||||
a11y::{
|
||||
accesskit::{Node as Accessible, Role},
|
||||
AccessibilityNode,
|
||||
},
|
||||
a11y::AccessibilityNode,
|
||||
input::mouse::{MouseScrollUnit, MouseWheel},
|
||||
picking::focus::HoverMap,
|
||||
prelude::*,
|
||||
|
|
|
@ -17,13 +17,13 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
// A unit struct to help identify the FPS UI component, since there may be many Text components
|
||||
// Marker struct to help identify the FPS UI component, since there may be many Text components
|
||||
#[derive(Component)]
|
||||
struct FpsText;
|
||||
|
||||
// A unit struct to help identify the color-changing Text component
|
||||
// Marker struct to help identify the color-changing Text component
|
||||
#[derive(Component)]
|
||||
struct ColorText;
|
||||
struct AnimatedText;
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// UI camera
|
||||
|
@ -47,7 +47,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
right: Val::Px(5.0),
|
||||
..default()
|
||||
},
|
||||
ColorText,
|
||||
AnimatedText,
|
||||
));
|
||||
|
||||
// Text with multiple sections
|
||||
|
@ -116,7 +116,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
));
|
||||
}
|
||||
|
||||
fn text_color_system(time: Res<Time>, mut query: Query<&mut TextColor, With<ColorText>>) {
|
||||
fn text_color_system(time: Res<Time>, mut query: Query<&mut TextColor, With<AnimatedText>>) {
|
||||
for mut text_color in &mut query {
|
||||
let seconds = time.elapsed_secs();
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
BackgroundColor(BLUE.into()),
|
||||
));
|
||||
parent.spawn((
|
||||
UiImage::new(asset_server.load("branding/icon.png")),
|
||||
ImageNode::new(asset_server.load("branding/icon.png")),
|
||||
Node {
|
||||
width: Val::Px(30.0),
|
||||
height: Val::Px(30.0),
|
||||
|
|
|
@ -44,7 +44,10 @@ fn setup(
|
|||
})
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
UiImage::from_atlas_image(texture_handle, TextureAtlas::from(texture_atlas_handle)),
|
||||
ImageNode::from_atlas_image(
|
||||
texture_handle,
|
||||
TextureAtlas::from(texture_atlas_handle),
|
||||
),
|
||||
Node {
|
||||
width: Val::Px(256.),
|
||||
height: Val::Px(256.),
|
||||
|
@ -64,10 +67,13 @@ fn setup(
|
|||
});
|
||||
}
|
||||
|
||||
fn increment_atlas_index(mut ui_images: Query<&mut UiImage>, keyboard: Res<ButtonInput<KeyCode>>) {
|
||||
fn increment_atlas_index(
|
||||
mut image_nodes: Query<&mut ImageNode>,
|
||||
keyboard: Res<ButtonInput<KeyCode>>,
|
||||
) {
|
||||
if keyboard.just_pressed(KeyCode::Space) {
|
||||
for mut ui_image in &mut ui_images {
|
||||
if let Some(atlas) = &mut ui_image.texture_atlas {
|
||||
for mut image_node in &mut image_nodes {
|
||||
if let Some(atlas) = &mut image_node.texture_atlas {
|
||||
atlas.index = (atlas.index + 1) % 6;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
|||
|
||||
fn button_system(
|
||||
mut interaction_query: Query<
|
||||
(&Interaction, &Children, &mut UiImage),
|
||||
(&Interaction, &Children, &mut ImageNode),
|
||||
(Changed<Interaction>, With<Button>),
|
||||
>,
|
||||
mut text_query: Query<&mut Text>,
|
||||
|
@ -82,7 +82,7 @@ fn setup(
|
|||
parent
|
||||
.spawn((
|
||||
Button,
|
||||
UiImage::from_atlas_image(
|
||||
ImageNode::from_atlas_image(
|
||||
texture_handle.clone(),
|
||||
TextureAtlas {
|
||||
index: idx,
|
||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
|||
|
||||
fn button_system(
|
||||
mut interaction_query: Query<
|
||||
(&Interaction, &Children, &mut UiImage),
|
||||
(&Interaction, &Children, &mut ImageNode),
|
||||
(Changed<Interaction>, With<Button>),
|
||||
>,
|
||||
mut text_query: Query<&mut Text>,
|
||||
|
@ -68,6 +68,11 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
parent
|
||||
.spawn((
|
||||
Button,
|
||||
ImageNode {
|
||||
image: image.clone(),
|
||||
image_mode: NodeImageMode::Sliced(slicer.clone()),
|
||||
..default()
|
||||
},
|
||||
Node {
|
||||
width: Val::Px(w),
|
||||
height: Val::Px(h),
|
||||
|
@ -78,8 +83,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
margin: UiRect::all(Val::Px(20.0)),
|
||||
..default()
|
||||
},
|
||||
UiImage::new(image.clone())
|
||||
.with_mode(NodeImageMode::Sliced(slicer.clone())),
|
||||
))
|
||||
.with_child((
|
||||
Text::new("Button"),
|
||||
|
|
|
@ -58,7 +58,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
([160., 160.], true, true),
|
||||
] {
|
||||
parent.spawn((
|
||||
UiImage {
|
||||
ImageNode {
|
||||
image: image.clone(),
|
||||
flip_x,
|
||||
flip_y,
|
||||
|
|
Loading…
Reference in a new issue