This adds a few minor items which were left out of the previous PR:
- Added synchronization from bevy_input_focus to bevy_a11y.
- Initialize InputFocusVisible resource.
- Make `input_focus` available from `bevy` module.
I've tested this using VoiceOver on Mac OS. It works, but it needs
considerable polish.
# Objective
- Fixes#16498
## Solution
- Trivially swaps ordering of hooks and observers for all call sites
where they are triggered for `on_replace` or `on_remove`
## Testing
- Just CI
---
## Migration Guide
The order of hooks and observers for `on_replace` and `on_remove` has
been swapped. Observers are now run before hooks. This is a more natural
ordering where the removal ordering is inverted compared to the
insertion ordering.
# Objective
Error handling in bevy is hard. See for reference
https://github.com/bevyengine/bevy/issues/11562,
https://github.com/bevyengine/bevy/issues/10874 and
https://github.com/bevyengine/bevy/issues/12660. The goal of this PR is
to make it better, by allowing users to optionally return `Result` from
systems as outlined by Cart in
<https://github.com/bevyengine/bevy/issues/14275#issuecomment-2223708314>.
## Solution
This PR introduces a new `ScheuleSystem` type to represent systems that
can be added to schedules. Instances of this type contain either an
infallible `BoxedSystem<(), ()>` or a fallible `BoxedSystem<(),
Result>`. `ScheuleSystem` implements `System<In = (), Out = Result>` and
replaces all uses of `BoxedSystem` in schedules. The async executor now
receives a result after executing a system, which for infallible systems
is always `Ok(())`. Currently it ignores this result, but more useful
error handling could also be implemented.
Aliases for `Error` and `Result` have been added to the `bevy_ecs`
prelude, as well as const `OK` which new users may find more friendly
than `Ok(())`.
## Testing
- Currently there are not actual semantics changes that really require
new tests, but I added a basic one just to make sure we don't break
stuff in the future.
- The behavior of existing systems is totally unchanged, including
logging.
- All of the existing systems tests pass, and I have not noticed
anything strange while playing with the examples
## Showcase
The following minimal example prints "hello world" once, then completes.
```rust
use bevy::prelude::*;
fn main() {
App::new().add_systems(Update, hello_world_system).run();
}
fn hello_world_system() -> Result {
println!("hello world");
Err("string")?;
println!("goodbye world");
OK
}
```
## Migration Guide
This change should be pretty much non-breaking, except for users who
have implemented their own custom executors. Those users should use
`ScheduleSystem` in place of `BoxedSystem<(), ()>` and import the
`System` trait where needed. They can choose to do whatever they wish
with the result.
## Current Work
+ [x] Fix tests & doc comments
+ [x] Write more tests
+ [x] Add examples
+ [X] Draft release notes
## Draft Release Notes
As of this release, systems can now return results.
First a bit of background: Bevy has hisotrically expected systems to
return the empty type `()`. While this makes sense in the context of the
ecs, it's at odds with how error handling is typically done in rust:
returning `Result::Error` to indicate failure, and using the
short-circuiting `?` operator to propagate that error up the call stack
to where it can be properly handled. Users of functional languages will
tell you this is called "monadic error handling".
Not being able to return `Results` from systems left bevy users with a
quandry. They could add custom error handling logic to every system, or
manually pipe every system into an error handler, or perhaps sidestep
the issue with some combination of fallible assignents, logging, macros,
and early returns. Often, users would just litter their systems with
unwraps and possible panics.
While any one of these approaches might be fine for a particular user,
each of them has their own drawbacks, and none makes good use of the
language. Serious issues could also arrise when two different crates
used by the same project made different choices about error handling.
Now, by returning results, systems can defer error handling to the
application itself. It looks like this:
```rust
// Previous, handling internally
app.add_systems(my_system)
fn my_system(window: Query<&Window>) {
let Ok(window) = query.get_single() else {
return;
};
// ... do something to the window here
}
// Previous, handling externally
app.add_systems(my_system.pipe(my_error_handler))
fn my_system(window: Query<&Window>) -> Result<(), impl Error> {
let window = query.get_single()?;
// ... do something to the window here
Ok(())
}
// Previous, panicking
app.add_systems(my_system)
fn my_system(window: Query<&Window>) {
let window = query.single();
// ... do something to the window here
}
// Now
app.add_systems(my_system)
fn my_system(window: Query<&Window>) -> Result {
let window = query.get_single()?;
// ... do something to the window here
Ok(())
}
```
There are currently some limitations. Systems must either return `()` or
`Result<(), Box<dyn Error + Send + Sync + 'static>>`, with no
in-between. Results are also ignored by default, and though implementing
a custom handler is possible, it involves writing your own custom ecs
executor (which is *not* recomended).
Systems should return errors when they cannot perform their normal
behavior. In turn, errors returned to the executor while running the
schedule will (eventually) be treated as unexpected. Users and library
authors should prefer to return errors for anything that disrupts the
normal expected behavior of a system, and should only handle expected
cases internally.
We have big plans for improving error handling further:
+ Allowing users to change the error handling logic of the default
executors.
+ Adding source tracking and optional backtraces to errors.
+ Possibly adding tracing-levels (Error/Warn/Info/Debug/Trace) to
errors.
+ Generally making the default error logging more helpful and
inteligent.
+ Adding monadic system combininators for fallible systems.
+ Possibly removing all panicking variants from our api.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
- This fixes raycast picking with lyon
- reverse winding of 2D meshes currently results in them being rendered
but not pickable as the raycast passes through the backface and would
only hit "from below"
## Solution
- Disables backface culling for Mesh2d
## Testing
- Tested picking with bevy_prototype_lyon
- Could probably use testing with Mesh3d (should not be affected) and
SimplifiedMesh (no experience with that, could have the same issue if
used for 2D?)
---------
Co-authored-by: Aevyrie <aevyrie@gmail.com>
The bindless PR (#16368) broke some examples:
* `specialized_mesh_pipeline` and `custom_shader_instancing` failed
because they expect to be able to render a mesh with no material, by
overriding enough of the render pipeline to be able to do so. This PR
fixes the issue by restoring the old behavior in which we extract meshes
even if they have no material.
* `texture_binding_array` broke because it doesn't implement
`AsBindGroup::unprepared_bind_group`. This was tricky to fix because
there's a very good reason why `texture_binding_array` doesn't implement
that method: there's no sensible way to do so with `wgpu`'s current
bindless API, due to its multiple levels of borrowed references. To fix
the example, I split `MaterialBindGroup` into
`MaterialBindlessBindGroup` and `MaterialNonBindlessBindGroup`, and
allow direct custom implementations of `AsBindGroup::as_bind_group` for
the latter type of bind groups. To opt in to the new behavior, return
the `AsBindGroupError::CreateBindGroupDirectly` error from your
`AsBindGroup::unprepared_bind_group` implementation, and Bevy will call
your custom `AsBindGroup::as_bind_group` method as before.
## Migration Guide
* Bevy will now unconditionally call
`AsBindGroup::unprepared_bind_group` for your materials, so you must no
longer panic in that function. Instead, return the new
`AsBindGroupError::CreateBindGroupDirectly` error, and Bevy will fall
back to calling `AsBindGroup::as_bind_group` as before.
# Objective
- Contributes to #15460
## Solution
- Added the following new features:
- `std` (default)
- `alloc`
- `encase` (default)
- `libm`
## Testing
- Added to `compile-check-no-std` CI command
## Notes
- `ColorCurve` requires `alloc` due to how the underlying `EvenCore`
type works.
- `Srgba::to_hex` requires `alloc` to return a `String`.
- This was otherwise a _very_ simple change
This commit moves the front end of the rendering pipeline to a retained
model when GPU preprocessing is in use (i.e. by default, except in
constrained environments). `RenderMeshInstance` and `MeshUniformData`
are stored from frame to frame and are updated only for the entities
that changed state. This was rather tricky and requires some careful
surgery to keep the data valid in the case of removals.
This patch is built on top of Bevy's change detection. Generally, this
worked, except that `ViewVisibility` isn't currently properly tracked.
Therefore, this commit adds proper change tracking for `ViewVisibility`.
Doing this required adding a new system that runs after all
`check_visibility` invocations, as no single `check_visibility`
invocation has enough global information to detect changes.
On the Bistro exterior scene, with all textures forced to opaque, this
patch improves steady-state `extract_meshes_for_gpu_building` from
93.8us to 34.5us and steady-state `collect_meshes_for_gpu_building` from
195.7us to 4.28us. Altogether this constitutes an improvement from 290us
to 38us, which is a 7.46x speedup.


This patch is only lightly tested and shouldn't land before 0.15 is
released anyway, so I'm releasing it as a draft.
# Objective
- Contributes to #15460
## Solution
- Added `std` feature (enabled by default)
## Testing
- CI
- `cargo check -p bevy_reflect --no-default-features --target
"x86_64-unknown-none"`
- UEFI demo application runs with this branch of `bevy_reflect`,
allowing `derive(Reflect)`
## Notes
- The [`spin`](https://crates.io/crates/spin) crate has been included to
provide `RwLock` and `Once` (as an alternative to `OnceLock`) when the
`std` feature is not enabled. Another alternative may be more desirable,
please provide feedback if you have a strong opinion here!
- Certain items (`Box`, `String`, `ToString`) provided by `alloc` have
been added to `__macro_exports` as a way to avoid `alloc` vs `std`
namespacing. I'm personally quite annoyed that we can't rely on `alloc`
as a crate name in `std` environments within macros. I'd love an
alternative to my approach here, but I suspect it's the least-bad
option.
- I would've liked to have an `alloc` feature (for allocation-free
`bevy_reflect`), unfortunately, `erased_serde` unconditionally requires
access to `Box`. Maybe one day we could design around this, but for now
it just means `bevy_reflect` requires `alloc`.
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
On the web, it's common to attach observers to windows. As @viridia has
discovered, this can be quite a nice paradigm in bevy as well when
applied to observers. The changes here are intended to make this
possible.
+ Adds a new default picking back-end as part to the core picking plugin
(which can be disabled) that causes pointers on windows to treat the
window entity as the final hit, behind everything else. This means
clicking empty space now dispatches normal picking events to the window,
and is especially nice for drag-and-drop functionality.
+ Adds a new traversal type, specific to picking events, that causes
them to bubble up to the window entity after they reach the root of the
hierarchy.
## Solution
The window picking back-end is extremely simple, but the bubbling
changes are much more complex, since they require doing a different
traversal depending on the picking event.
To achieve this, `Traversal` has been made generic over an associated
sized data type `D`. Observer bounds have been changed such that
`Event::Traversal<D>` is required for `Trigger<D>`. A blanket
implementation has been added for `()` and `Parent` that preserves the
existing functionality. A new `PointerTraversal` traversal has been
implemented, with a blanket implementation for `Traversal<Pointer<E>>`.
It is still possible to use `Parent` as the traversal for any event,
because of the blanket implementation. It is now possible for users to
add other custom traversals, which read event data during traversal.
## Testing
I tested these changes locally on some picking UI prototypes I have been
playing with. I also tested them on the picking examples.
---------
Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
# Objective
- Currently adding observers spawns an entity which implicitly flushes
the command queue, which can cause undefined behaviour if the
`WorldEntityMut` is used after this
- The reason `WorldEntityMut` attempted to (unsuccessfully) avoid
flushing commands until finished was that such commands may move or
despawn the entity being referenced, invalidating the cached location.
- With the introduction of hooks and observers, this isn't sensible
anymore as running the commands generated by hooks immediately is
required to maintain correct ordering of operations and to not expose
the world in an inconsistent state
- Objective is to make command flushing deterministic and fix the
related issues
- Fixes#16212
- Fixes#14621
- Fixes#16034
## Solution
- Allow `WorldEntityMut` to exist even when it refers to a despawned
entity by allowing `EntityLocation` to be marked invalid
- Add checks to all methods to panic if trying to access a despawned
entity
- Flush command queue after every operation that might trigger hooks or
observers
- Update entity location always after flushing command queue
## Testing
- Added test cases for currently broken behaviour
- Added test cases that flushes happen in all operations
- Added test cases to ensure hooks and commands are run exactly in
correct order when nested
---
Todo:
- [x] Write migration guide
- [x] Add tests that using `EntityWorldMut` on a despawned entity panics
- [x] Add tests that commands are flushed after every operation that is
supposed to flush them
- [x] Add tests that hooks, observers and their spawned commands are run
in the correct order when nested
---
## Migration Guide
Previously `EntityWorldMut` triggered command queue flushes in
unpredictable places, which could interfere with hooks and observers.
Now the command queue is flushed always immediately after any call in
`EntityWorldMut` that spawns or despawns an entity, or adds, removes or
replaces a component. This means hooks and observers will run their
commands in the correct order.
As a side effect, there is a possibility that a hook or observer could
despawn the entity that is being referred to by `EntityWorldMut`. This
could already currently happen if an observer was added while keeping an
`EntityWorldMut` referece and would cause unsound behaviour. If the
entity has been despawned, calling any methods which require the entity
location will panic. This matches the behaviour that `Commands` will
panic if called on an already despawned entity. In the extremely rare
case where taking a new `EntityWorldMut` reference or otherwise
restructuring the code so that this case does not happen is not
possible, there's a new `is_despawned` method that can be used to check
if the referred entity has been despawned.
# Objective
- Required by #16622 due to differing implementations of `System` by
`FunctionSystem` and `ExclusiveFunctionSystem`.
- Optimize the memory usage of instances of `apply_deferred` in system
schedules.
## Solution
By changing `apply_deferred` from being an ordinary system that ends up
as an `ExclusiveFunctionSystem`, and instead into a ZST struct that
implements `System` manually, we save ~320 bytes per instance of
`apply_deferred` in any schedule.
## Testing
- All current tests pass.
---
## Migration Guide
- If you were previously calling the special `apply_deferred` system via
`apply_deferred(world)`, don't.
# Objective
Outside of the `bevy_ecs` crate it's hard to implement `SystemParam`
trait on params that require access to the `World`, because `init_state`
expects user to extend access in `SystemMeta` and access-related fields
of `SystemMeta` are private.
## Solution
Expose those fields as a functions
# Objective
Define a framework for handling keyboard focus and bubbled keyboard
events, as discussed in #15374.
## Solution
Introduces a new crate, `bevy_input_focus`. This crate provides:
* A resource for tracking which entity has keyboard focus.
* Methods for getting and setting keyboard focus.
* Event definitions for triggering bubble-able keyboard input events to
the focused entity.
* A system for dispatching keyboard input events to the focused entity.
This crate does *not* provide any integration with UI widgets, or
provide functions for
tab navigation or gamepad-based focus navigation, as those are typically
application-specific.
## Testing
Most of the code has been copied from a different project, one that has
been well tested. However, most of what's in this module consists of
type definitions, with relatively small amounts of executable code. That
being said, I expect that there will be substantial bikeshedding on the
design, and I would prefer to hold off writing tests until after things
have settled.
I think that an example would be appropriate, however I'm waiting on a
few other pending changes to Bevy before doing so. In particular, I can
see a simple example with four buttons, with focus navigation between
them, and which can be triggered by the keyboard.
@alice-i-cecile
# Objective
- Fixes#16208
## Solution
- Added an associated type to `Component`, `Mutability`, which flags
whether a component is mutable, or immutable. If `Mutability= Mutable`,
the component is mutable. If `Mutability= Immutable`, the component is
immutable.
- Updated `derive_component` to default to mutable unless an
`#[component(immutable)]` attribute is added.
- Updated `ReflectComponent` to check if a component is mutable and, if
not, panic when attempting to mutate.
## Testing
- CI
- `immutable_components` example.
---
## Showcase
Users can now mark a component as `#[component(immutable)]` to prevent
safe mutation of a component while it is attached to an entity:
```rust
#[derive(Component)]
#[component(immutable)]
struct Foo {
// ...
}
```
This prevents creating an exclusive reference to the component while it
is attached to an entity. This is particularly powerful when combined
with component hooks, as you can now fully track a component's value,
ensuring whatever invariants you desire are upheld. Before this would be
done my making a component private, and manually creating a `QueryData`
implementation which only permitted read access.
<details>
<summary>Using immutable components as an index</summary>
```rust
/// This is an example of a component like [`Name`](bevy::prelude::Name), but immutable.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Component)]
#[component(
immutable,
on_insert = on_insert_name,
on_replace = on_replace_name,
)]
pub struct Name(pub &'static str);
/// This index allows for O(1) lookups of an [`Entity`] by its [`Name`].
#[derive(Resource, Default)]
struct NameIndex {
name_to_entity: HashMap<Name, Entity>,
}
impl NameIndex {
fn get_entity(&self, name: &'static str) -> Option<Entity> {
self.name_to_entity.get(&Name(name)).copied()
}
}
fn on_insert_name(mut world: DeferredWorld<'_>, entity: Entity, _component: ComponentId) {
let Some(&name) = world.entity(entity).get::<Name>() else {
unreachable!()
};
let Some(mut index) = world.get_resource_mut::<NameIndex>() else {
return;
};
index.name_to_entity.insert(name, entity);
}
fn on_replace_name(mut world: DeferredWorld<'_>, entity: Entity, _component: ComponentId) {
let Some(&name) = world.entity(entity).get::<Name>() else {
unreachable!()
};
let Some(mut index) = world.get_resource_mut::<NameIndex>() else {
return;
};
index.name_to_entity.remove(&name);
}
// Setup our name index
world.init_resource::<NameIndex>();
// Spawn some entities!
let alyssa = world.spawn(Name("Alyssa")).id();
let javier = world.spawn(Name("Javier")).id();
// Check our index
let index = world.resource::<NameIndex>();
assert_eq!(index.get_entity("Alyssa"), Some(alyssa));
assert_eq!(index.get_entity("Javier"), Some(javier));
// Changing the name of an entity is also fully capture by our index
world.entity_mut(javier).insert(Name("Steven"));
// Javier changed their name to Steven
let steven = javier;
// Check our index
let index = world.resource::<NameIndex>();
assert_eq!(index.get_entity("Javier"), None);
assert_eq!(index.get_entity("Steven"), Some(steven));
```
</details>
Additionally, users can use `Component<Mutability = ...>` in trait
bounds to enforce that a component _is_ mutable or _is_ immutable. When
using `Component` as a trait bound without specifying `Mutability`, any
component is applicable. However, methods which only work on mutable or
immutable components are unavailable, since the compiler must be
pessimistic about the type.
## Migration Guide
- When implementing `Component` manually, you must now provide a type
for `Mutability`. The type `Mutable` provides equivalent behaviour to
earlier versions of `Component`:
```rust
impl Component for Foo {
type Mutability = Mutable;
// ...
}
```
- When working with generic components, you may need to specify that
your generic parameter implements `Component<Mutability = Mutable>`
rather than `Component` if you require mutable access to said component.
- The entity entry API has had to have some changes made to minimise
friction when working with immutable components. Methods which
previously returned a `Mut<T>` will now typically return an
`OccupiedEntry<T>` instead, requiring you to add an `into_mut()` to get
the `Mut<T>` item again.
## Draft Release Notes
Components can now be made immutable while stored within the ECS.
Components are the fundamental unit of data within an ECS, and Bevy
provides a number of ways to work with them that align with Rust's rules
around ownership and borrowing. One part of this is hooks, which allow
for defining custom behavior at key points in a component's lifecycle,
such as addition and removal. However, there is currently no way to
respond to _mutation_ of a component using hooks. The reasons for this
are quite technical, but to summarize, their addition poses a
significant challenge to Bevy's core promises around performance.
Without mutation hooks, it's relatively trivial to modify a component in
such a way that breaks invariants it intends to uphold. For example, you
can use `core::mem::swap` to swap the components of two entities,
bypassing the insertion and removal hooks.
This means the only way to react to this modification is via change
detection in a system, which then begs the question of what happens
_between_ that alteration and the next run of that system?
Alternatively, you could make your component private to prevent
mutation, but now you need to provide commands and a custom `QueryData`
implementation to allow users to interact with your component at all.
Immutable components solve this problem by preventing the creation of an
exclusive reference to the component entirely. Without an exclusive
reference, the only way to modify an immutable component is via removal
or replacement, which is fully captured by component hooks. To make a
component immutable, simply add `#[component(immutable)]`:
```rust
#[derive(Component)]
#[component(immutable)]
struct Foo {
// ...
}
```
When implementing `Component` manually, there is an associated type
`Mutability` which controls this behavior:
```rust
impl Component for Foo {
type Mutability = Mutable;
// ...
}
```
Note that this means when working with generic components, you may need
to specify that a component is mutable to gain access to certain
methods:
```rust
// Before
fn bar<C: Component>() {
// ...
}
// After
fn bar<C: Component<Mutability = Mutable>>() {
// ...
}
```
With this new tool, creating index components, or caching data on an
entity should be more user friendly, allowing libraries to provide APIs
relying on components and hooks to uphold their invariants.
## Notes
- ~~I've done my best to implement this feature, but I'm not happy with
how reflection has turned out. If any reflection SMEs know a way to
improve this situation I'd greatly appreciate it.~~ There is an
outstanding issue around the fallibility of mutable methods on
`ReflectComponent`, but the DX is largely unchanged from `main` now.
- I've attempted to prevent all safe mutable access to a component that
does not implement `Component<Mutability = Mutable>`, but there may
still be some methods I have missed. Please indicate so and I will
address them, as they are bugs.
- Unsafe is an escape hatch I am _not_ attempting to prevent. Whatever
you do with unsafe is between you and your compiler.
- I am marking this PR as ready, but I suspect it will undergo fairly
major revisions based on SME feedback.
- I've marked this PR as _Uncontroversial_ based on the feature, not the
implementation.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: Nuutti Kotivuori <naked@iki.fi>
This commit allows the Bevy renderer to use the clustering
infrastructure for light probes (reflection probes and irradiance
volumes) on platforms where at least 3 storage buffers are available. On
such platforms (the vast majority), we stop performing brute-force
searches of light probes for each fragment and instead only search the
light probes with bounding spheres that intersect the current cluster.
This should dramatically improve scalability of irradiance volumes and
reflection probes.
The primary platform that doesn't support 3 storage buffers is WebGL 2,
and we continue using a brute-force search of light probes on that
platform, as the UBO that stores per-cluster indices is too small to fit
the light probe counts. Note, however, that that platform also doesn't
support bindless textures (indeed, it would be very odd for a platform
to support bindless textures but not SSBOs), so we only support one of
each type of light probe per drawcall there in the first place.
Consequently, this isn't a performance problem, as the search will only
have one light probe to consider. (In fact, clustering would probably
end up being a performance loss.)
Known potential improvements include:
1. We currently cull based on a conservative bounding sphere test and
not based on the oriented bounding box (OBB) of the light probe. This is
improvable, but in the interests of simplicity, I opted to keep the
bounding sphere test for now. The OBB improvement can be a follow-up.
2. This patch doesn't change the fact that each fragment only takes a
single light probe into account. Typical light probe implementations
detect the case in which multiple light probes cover the current
fragment and perform some sort of weighted blend between them. As the
light probe fetch function presently returns only a single light probe,
implementing that feature would require more code restructuring, so I
left it out for now. It can be added as a follow-up.
3. Light probe implementations typically have a falloff range. Although
this is a wanted feature in Bevy, this particular commit also doesn't
implement that feature, as it's out of scope.
4. This commit doesn't raise the maximum number of light probes past its
current value of 8 for each type. This should be addressed later, but
would possibly require more bindings on platforms with storage buffers,
which would increase this patch's complexity. Even without raising the
limit, this patch should constitute a significant performance
improvement for scenes that get anywhere close to this limit. In the
interest of keeping this patch small, I opted to leave raising the limit
to a follow-up.
## Changelog
### Changed
* Light probes (reflection probes and irradiance volumes) are now
clustered on most platforms, improving performance when many light
probes are present.
---------
Co-authored-by: Benjamin Brienen <Benjamin.Brienen@outlook.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Add a way to use the gizmo API in a retained manner, for increased
performance.
## Solution
- Move gizmo API from `Gizmos` to `GizmoBuffer`, ~ab~using `Deref` to
keep usage the same as before.
- Merge non-strip and strip variant of `LineGizmo` into one, storing the
data in a `GizmoBuffer` to have the same API for retained `LineGizmo`s.
### Review guide
- The meat of the changes are in `lib.rs`, `retained.rs`, `gizmos.rs`,
`pipeline_3d.rs` and `pipeline_2d.rs`
- The other files contain almost exclusively the churn from moving the
gizmo API from `Gizmos` to `GizmoBuffer`
## Testing
### Performance
Performance compared to the immediate mode API is from 65 to 80 times
better for static lines.
```
7900 XTX, 3700X
1707.9k lines/ms: gizmos_retained (21.3ms)
3488.5k lines/ms: gizmos_retained_continuous_polyline (31.3ms)
0.5k lines/ms: gizmos_retained_separate (97.7ms)
3054.9k lines/ms: bevy_polyline_retained_nan (16.8ms)
3596.3k lines/ms: bevy_polyline_retained_continuous_polyline (14.2ms)
0.6k lines/ms: bevy_polyline_retained_separate (78.9ms)
26.9k lines/ms: gizmos_immediate (14.9ms)
43.8k lines/ms: gizmos_immediate_continuous_polyline (18.3ms)
```
Looks like performance is good enough, being close to par with
`bevy_polyline`.
Benchmarks can be found here:
This branch:
https://github.com/tim-blackbird/line_racing/tree/retained-gizmos
Bevy 0.14: https://github.com/DGriffin91/line_racing
## Showcase
```rust
fn setup(
mut commands: Commands,
mut gizmo_assets: ResMut<Assets<GizmoAsset>>
) {
let mut gizmo = GizmoAsset::default();
// A sphere made out of one million lines!
gizmo
.sphere(default(), 1., CRIMSON)
.resolution(1_000_000 / 3);
commands.spawn(Gizmo {
handle: gizmo_assets.add(gizmo),
..default()
});
}
```
## Follow-up work
- Port over to the retained rendering world proper
- Calculate visibility and cull `Gizmo`s
# Objective
BrpQueryRow doesn't serialize `has` field if it is empty. That is okay
until you try to deserialize it after. Then it will fail to deserialize
due to missing field.
## Solution
Serde support using default value when field is missing, this PR adds
that.
# Objective
Fix a [Blenvy](https://github.com/kaosat-dev/Blenvy) crash due to a
missing type registration for `TextEntity` (as the type is used by
`ComputedTextBlock` but wasn't itself registered.)
## Solution
- Added the missing type registration
## Testing
- N/A
Currently, the prepass has no support for visibility ranges, so
artifacts appear when using dithering visibility ranges in conjunction
with a prepass. This patch fixes that problem.
Note that this patch changes the prepass to use sparse bind group
indices instead of sequential ones. I figured this is cleaner, because
it allows for greater sharing of WGSL code between the forward pipeline
and the prepass pipeline.
The `visibility_range` example has been updated to allow the prepass to
be toggled on and off.
# Objective
- Contributes to #15460
## Solution
- Removed `petgraph` as a dependency from the `bevy_ecs` crate.
- Replaced `TarjanScc` and `GraphMap` with specialised in-tree
alternatives.
## Testing
- Ran CI locally.
- Added new unit tests to check ordering invariants.
- Confirmed `petgraph` is no longer present in `cargo tree -p bevy_ecs`
## Migration Guide
The `Dag::graph` method no longer returns a `petgraph` `DiGraph` and
instead returns the new `DiGraph` type within `bevy_ecs`. Edge and node
iteration methods are provided so conversion to the `petgraph` type
should be trivial if required.
## Notes
- `indexmap` was already in the dependency graph for `bevy_ecs`, so its
inclusion here makes no difference to compilation time for Bevy.
- The implementation for `Graph` is heavily inspired from the `petgraph`
original, with specialisations added to simplify and improve the type.
- `petgraph` does have public plans for `no_std` support, however there
is no timeframe on if or when that functionality will be available.
Moving to an in-house solution in the interim allows Bevy to continue
developing its `no_std` offerings and further explore alternate graphing
options.
---------
Co-authored-by: Lixou <82600264+DasLixou@users.noreply.github.com>
Co-authored-by: vero <11307157+atlv24@users.noreply.github.com>
# Objective
- dont depend on wgpu if we dont have to
## Solution
- works towards this, but doesnt fully accomplish it. bevy_mesh depends
on bevy_image
## Testing
- 3d_scene runs
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
# Objective
- Fixes#16594
## Solution
- `StateTransitionSteps` was made public
## Testing
- _Did you test these changes? If so, how?_
I am now able to import it and use it.
---
## Showcase
- Users can now write their own state scoped resources
```rust
fn init_state_scoped_resource<R: Resource + FromWorld>(
&mut self,
state: impl States,
) -> &mut Self {
use bevy::state::state::StateTransitionSteps; // this PR in action
self.add_systems(
StateTransition,
(
clear_state_scoped_resource_impl::<_, R>(state.clone())
.in_set(StateTransitionSteps::ExitSchedules), // and here
init_state_scoped_resource_impl::<_, R>(state)
.in_set(StateTransitionSteps::EnterSchedules), // here too
),
);
self
}
```
# Objective
Make documentation of a component's required components more visible by
moving it to the type's docs
## Solution
Change `#[require]` from a derive macro helper to an attribute macro.
Disadvantages:
- this silences any unused code warnings on the component, as it is used
by the macro!
- need to import `require` if not using the ecs prelude (I have not
included this in the migration guilde as Rust tooling already suggests
the fix)
---
## Showcase

---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
# Objective
The `UiBoxShadowSamples` resource should be renamed to
`BoxShadowSamples` so it matches the `BoxShadow` component.
## Migration Guide
`UiBoxShadowSamples` has been renamed to `BoxShadowSamples`
# Objective
`flush_and_reserve_invalid_assuming_no_entities` was made for the old
rendering world (which was reset every frame) and is usused since the
0.15 retained rendering world, but wasn't removed yet. It is pub, but is
undocumented apart from the safety comment.
## Solution
Remove `flush_and_reserve_invalid_assuming_no_entities` and the safety
invariants this method required for `EntityMeta`, `EntityLocation`,
`TableId` and `TableRow`. This reduces the amount of unsafe code &
safety invariants and makes #16047 easier.
## Alternatives
- Document `flush_and_reserve_invalid_assuming_no_entities` and keep it
unchanged
- Document `flush_and_reserve_invalid_assuming_no_entities` and change
it to be based on `EntityMeta::INVALID`
## Migration Guide
- exchange `Entities::flush_and_reserve_invalid_assuming_no_entities`
for `reserve` and `flush_as_invalid` and notify us if that's
insufficient
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# Objective
Remove the `min` and `max` fields from `LayoutContext`.
It doesn't seem useful to cache these values, it's simpler just to call
`min_element` and `max_element` on the `physical_size`
field.
## Migration Guide
The `min` and `max` fields have been removed from `LayoutContext`. To
retrieve these values call `min_element` and `max_element` on
`LayoutContent::physical_size` instead.
# Objective
This was always a bit weird; `IntoIterator` is considered more idiomatic
in Rust.
The reason these used `Into<Vec<..>>` in the first place was (to my
knowledge) because of concerns that passing an already-owned vector
would cause a redundant allocation if the iterator API was used instead.
However, I have looked at simple examples for this scenario and the
generated assembly is identical (i.e. `into_iter().collect()` is
effectively converted to a no-op).
## Solution
As described in the title.
## Testing
It compiles. Ran existing tests.
## Migration Guide
The cubic splines API now uses `IntoIterator` in places where it used
`Into<Vec<..>>`. For most users, this will have little to no effect (it
is largely more permissive). However, in case you were using some
unusual input type that implements `Into<Vec<..>>` without implementing
`IntoIterator`, you can migrate by converting the input to a `Vec<..>`
before passing it into the interface.
# Objective
- Allow bevy_sprite_picking backend to pass through transparent sections
of the sprite.
- Fixes#14929
## Solution
- After sprite picking detects the cursor is within a sprites rect,
check the pixel at that location on the texture and check that it meets
an optional transparency cutoff. Change originally created for
mod_picking on bevy 0.14
(https://github.com/aevyrie/bevy_mod_picking/pull/373)
## Testing
- Ran Sprite Picking example to check it was working both with
transparency enabled and disabled
- ModPicking version is currently in use in my own isometric game where
this has been an extremely noticeable issue
## Showcase

## Migration Guide
Sprite picking now ignores transparent regions (with an alpha value less
than or equal to 0.1). To configure this, modify the
`SpriteBackendSettings` resource.
---------
Co-authored-by: andriyDev <andriydzikh@gmail.com>
This patch adds the infrastructure necessary for Bevy to support
*bindless resources*, by adding a new `#[bindless]` attribute to
`AsBindGroup`.
Classically, only a single texture (or sampler, or buffer) can be
attached to each shader binding. This means that switching materials
requires breaking a batch and issuing a new drawcall, even if the mesh
is otherwise identical. This adds significant overhead not only in the
driver but also in `wgpu`, as switching bind groups increases the amount
of validation work that `wgpu` must do.
*Bindless resources* are the typical solution to this problem. Instead
of switching bindings between each texture, the renderer instead
supplies a large *array* of all textures in the scene up front, and the
material contains an index into that array. This pattern is repeated for
buffers and samplers as well. The renderer now no longer needs to switch
binding descriptor sets while drawing the scene.
Unfortunately, as things currently stand, this approach won't quite work
for Bevy. Two aspects of `wgpu` conspire to make this ideal approach
unacceptably slow:
1. In the DX12 backend, all binding arrays (bindless resources) must
have a constant size declared in the shader, and all textures in an
array must be bound to actual textures. Changing the size requires a
recompile.
2. Changing even one texture incurs revalidation of all textures, a
process that takes time that's linear in the total size of the binding
array.
This means that declaring a large array of textures big enough to
encompass the entire scene is presently unacceptably slow. For example,
if you declare 4096 textures, then `wgpu` will have to revalidate all
4096 textures if even a single one changes. This process can take
multiple frames.
To work around this problem, this PR groups bindless resources into
small *slabs* and maintains a free list for each. The size of each slab
for the bindless arrays associated with a material is specified via the
`#[bindless(N)]` attribute. For instance, consider the following
declaration:
```rust
#[derive(AsBindGroup)]
#[bindless(16)]
struct MyMaterial {
#[buffer(0)]
color: Vec4,
#[texture(1)]
#[sampler(2)]
diffuse: Handle<Image>,
}
```
The `#[bindless(N)]` attribute specifies that, if bindless arrays are
supported on the current platform, each resource becomes a binding array
of N instances of that resource. So, for `MyMaterial` above, the `color`
attribute is exposed to the shader as `binding_array<vec4<f32>, 16>`,
the `diffuse` texture is exposed to the shader as
`binding_array<texture_2d<f32>, 16>`, and the `diffuse` sampler is
exposed to the shader as `binding_array<sampler, 16>`. Inside the
material's vertex and fragment shaders, the applicable index is
available via the `material_bind_group_slot` field of the `Mesh`
structure. So, for instance, you can access the current color like so:
```wgsl
// `uniform` binding arrays are a non-sequitur, so `uniform` is automatically promoted
// to `storage` in bindless mode.
@group(2) @binding(0) var<storage> material_color: binding_array<Color, 4>;
...
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let color = material_color[mesh[in.instance_index].material_bind_group_slot];
...
}
```
Note that portable shader code can't guarantee that the current platform
supports bindless textures. Indeed, bindless mode is only available in
Vulkan and DX12. The `BINDLESS` shader definition is available for your
use to determine whether you're on a bindless platform or not. Thus a
portable version of the shader above would look like:
```wgsl
#ifdef BINDLESS
@group(2) @binding(0) var<storage> material_color: binding_array<Color, 4>;
#else // BINDLESS
@group(2) @binding(0) var<uniform> material_color: Color;
#endif // BINDLESS
...
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
#ifdef BINDLESS
let color = material_color[mesh[in.instance_index].material_bind_group_slot];
#else // BINDLESS
let color = material_color;
#endif // BINDLESS
...
}
```
Importantly, this PR *doesn't* update `StandardMaterial` to be bindless.
So, for example, `scene_viewer` will currently not run any faster. I
intend to update `StandardMaterial` to use bindless mode in a follow-up
patch.
A new example, `shaders/shader_material_bindless`, has been added to
demonstrate how to use this new feature.
Here's a Tracy profile of `submit_graph_commands` of this patch and an
additional patch (not submitted yet) that makes `StandardMaterial` use
bindless. Red is those patches; yellow is `main`. The scene was Bistro
Exterior with a hack that forces all textures to opaque. You can see a
1.47x mean speedup.

## Migration Guide
* `RenderAssets::prepare_asset` now takes an `AssetId` parameter.
* Bin keys now have Bevy-specific material bind group indices instead of
`wgpu` material bind group IDs, as part of the bindless change. Use the
new `MaterialBindGroupAllocator` to map from bind group index to bind
group ID.
# Objective
Fixes#15941
## Solution
Created https://crates.io/crates/variadics_please and moved the code
there; updating references
`bevy_utils/macros` is deleted.
## Testing
cargo check
## Migration Guide
Use `variadics_please::{all_tuples, all_tuples_with_size}` instead of
`bevy::utils::{all_tuples, all_tuples_with_size}`.
## Objective
Fixes#1515
This PR implements a flexible entity cloning system. The primary use
case for it is to clone dynamically-generated entities.
Example:
```rs
#[derive(Component, Clone)]
pub struct Projectile;
#[derive(Component, Clone)]
pub struct Damage {
value: f32,
}
fn player_input(
mut commands: Commands,
projectiles: Query<Entity, With<Projectile>>,
input: Res<ButtonInput<KeyCode>>,
) {
// Fire a projectile
if input.just_pressed(KeyCode::KeyF) {
commands.spawn((Projectile, Damage { value: 10.0 }));
}
// Triplicate all active projectiles
if input.just_pressed(KeyCode::KeyT) {
for projectile in projectiles.iter() {
// To triplicate a projectile we need to create 2 more clones
for _ in 0..2{
commands.clone_entity(projectile)
}
}
}
}
```
## Solution
### Commands
Add a `clone_entity` command to create a clone of an entity with all
components that can be cloned. Components that can't be cloned will be
ignored.
```rs
commands.clone_entity(entity)
```
If there is a need to configure the cloning process (like set to clone
recursively), there is a second command:
```rs
commands.clone_entity_with(entity, |builder| {
builder.recursive(true)
});
```
Both of these commands return `EntityCommands` of the cloned entity, so
the copy can be modified afterwards.
### Builder
All these commands use `EntityCloneBuilder` internally. If there is a
need to clone an entity using `World` instead, it is also possible:
```rs
let entity = world.spawn(Component).id();
let entity_clone = world.spawn_empty().id();
EntityCloneBuilder::new(&mut world).clone_entity(entity, entity_clone);
```
Builder has methods to `allow` or `deny` certain components during
cloning if required and can be extended by implementing traits on it.
This PR includes two `EntityCloneBuilder` extensions:
`CloneEntityWithObserversExt` to configure adding cloned entity to
observers of the original entity, and `CloneEntityRecursiveExt` to
configure cloning an entity recursively.
### Clone implementations
By default, all components that implement either `Clone` or `Reflect`
will be cloned (with `Clone`-based implementation preferred in case
component implements both).
This can be overriden on a per-component basis:
```rs
impl Component for SomeComponent {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn get_component_clone_handler() -> ComponentCloneHandler {
// Don't clone this component
ComponentCloneHandler::Ignore
}
}
```
### `ComponentCloneHandlers`
Clone implementation specified in `get_component_clone_handler` will get
registered in `ComponentCloneHandlers` (stored in
`bevy_ecs::component::Components`) at component registration time.
The clone handler implementation provided by a component can be
overriden after registration like so:
```rs
let component_id = world.components().component_id::<Component>().unwrap()
world.get_component_clone_handlers_mut()
.set_component_handler(component_id, ComponentCloneHandler::Custom(component_clone_custom))
```
The default clone handler for all components that do not explicitly
define one (or don't derive `Component`) is
`component_clone_via_reflect` if `bevy_reflect` feature is enabled, and
`component_clone_ignore` (noop) otherwise.
Default handler can be overriden using
`ComponentCloneHandlers::set_default_handler`
### Handlers
Component clone handlers can be used to modify component cloning
behavior. The general signature for a handler that can be used in
`ComponentCloneHandler::Custom` is as follows:
```rs
pub fn component_clone_custom(
world: &mut DeferredWorld,
entity_cloner: &EntityCloner,
) {
// implementation
}
```
The `EntityCloner` implementation (used internally by
`EntityCloneBuilder`) assumes that after calling this custom handler,
the `target` entity has the desired version of the component from the
`source` entity.
### Builder handler overrides
Besides component-defined and world-overriden handlers,
`EntityCloneBuilder` also has a way to override handlers locally. It is
mainly used to allow configuration methods like `recursive` and
`add_observers`.
```rs
// From observer clone handler implementation
impl CloneEntityWithObserversExt for EntityCloneBuilder<'_> {
fn add_observers(&mut self, add_observers: bool) -> &mut Self {
if add_observers {
self.override_component_clone_handler::<ObservedBy>(ComponentCloneHandler::Custom(
component_clone_observed_by,
))
} else {
self.remove_component_clone_handler_override::<ObservedBy>()
}
}
}
```
## Testing
Includes some basic functionality tests and doctests.
Performance-wise this feature is the same as calling `clone` followed by
`insert` for every entity component. There is also some inherent
overhead due to every component clone handler having to access component
data through `World`, but this can be reduced without breaking current
public API in a later PR.
# Objective
- Fixes#16078
## Solution
- Rename things to clarify that we _want_ unclipped depth for
directional light shadow views, and need some way of disabling the GPU's
builtin depth clipping
- Use DEPTH_CLIP_CONTROL instead of the fragment shader emulation on
supported platforms
- Pass only the clip position depth instead of the whole clip position
between vertex->fragment shader (no idea if this helps performance or
not, compiler might optimize it anyways)
- Meshlets
- HW raster always uses DEPTH_CLIP_CONTROL since it targets a more
limited set of platforms
- SW raster was not handling DEPTH_CLAMP_ORTHO correctly, it ended up
pretty much doing nothing.
- This PR made me realize that SW raster technically should have depth
clipping for all views that are not directional light shadows, but I
decided not to bother writing it. I'm not sure that it ever matters in
practice. If proven otherwise, I can add it.
## Testing
- Did you test these changes? If so, how?
- Lighting example. Both opaque (no fragment shader) and alpha masked
geometry (fragment shader emulation) are working with
depth_clip_control, and both work when it's turned off. Also tested
meshlet example.
- Are there any parts that need more testing?
- Performance. I can't figure out a good test scene.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Toggle depth_clip_control_supported in prepass/mod.rs line 323 to turn
this PR on or off.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Native
---
## Migration Guide
- `MeshPipelineKey::DEPTH_CLAMP_ORTHO` is now
`MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO`
- The `DEPTH_CLAMP_ORTHO` shaderdef has been renamed to
`UNCLIPPED_DEPTH_ORTHO_EMULATION`
- `clip_position_unclamped: vec4<f32>` is now `unclipped_depth: f32`
# Objective
Avoid a premature normalize operation and get better smooth normals for
it.
## Inspiration
@IceSentry suggested `face_normal()` could have its normalize removed
based on [this article](https://iquilezles.org/articles/normals/) in PR
#16039.
## Solution
I did not want to change `face_normal()` to return a vector that's not
normalized. The name "normal" implies it'll be normalized. Instead I
added the `face_area_normal()` function, whose result is not normalized.
Its magnitude is equal two times the triangle's area. I've noted why
this is the case in its doc comment.
I changed `compute_smooth_normals()` from computing normals from
adjacent faces with equal weight to use the area of the faces as a
weight. This has the benefit of being cheaper computationally and
hopefully produces better normals.
The `compute_flat_normals()` is unchanged and still uses
`face_normal()`.
## Testing
One test was added which shows the bigger triangle having an effect on
the normal, but the previous test that uses the same size triangles is
unchanged.
**WARNING:** No visual test has been done yet. No example exists that
demonstrates the compute_smooth_normals(). Perhaps there's a good model
to demonstrate what the differences are. I would love to have some input
on this.
I'd suggest @IceSentry and @stepancheg to review this PR.
## Further Considerations
It's possible weighting normals by their area is not definitely better
than unweighted. It's possible there may be aesthetic reasons to prefer
one over the other. In such a case, we could offer two variants:
weighted or unweighted. Or we could offer another function perhaps like
this: `compute_smooth_normals_with_weights(|normal, area| 1.0)` which
would restore the original unweighted sum of normals.
---
## Showcase
Smooth normal calculation now weights adjacent face normals by their
area.
## Migration Guide
# Objective
- Exposes raw winit events making Bevy even more modular and powerful
for custom plugin developers (e.g. a custom render plugin).
XRef: https://github.com/bevyengine/bevy/issues/5977
It doesn't quite close the issue as sending events is not supported (or
not very useful to be precise). I would think that supporting that
requires some extra considerations by someone a bit more familiar with
the `bevy_winit` crate. That said, this PR could be a nice step forward.
## Solution
Emit `RawWinitWindowEvent` objects for each received event.
## Testing
I verified that the events are emitted using a basic test app. I don't
think it makes sense to solidify this behavior in one of the examples.
---
## Showcase
My example usage for a custom `egui_winit` integration:
```rust
for ev in winit_events.read() {
if ev.window_id == window.id {
let _ = egui_winit.on_window_event(&window, &ev.event);
}
}
```
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
- Keep Taffy version up to date
Taffy 0.6 doesn't include a huge amount relevant to Bevy. But it does:
- Add the `box_sizing` style
- Expose the computed `margin` in layout
- Traitifies the `Style` struct, which opens up the possibility of using
Bevy's `Style` struct directly (although Bevy currently does some style
resolution at conversion time which would no longer be cached if it was
used directly).
- Have a few bug fixes in the layout algorithms
## Solution
- Upgrade Taffy to `0.6.0`
## Testing
- I've run the `grid` example. All looks good.
- More testing is probably warranted. We have had regressions from Taffy
upgrades before
- Having said that, most of the algorithm changes this cycle were driven
by fixing WPT tests run through the new Servo integration. So they're
possibly less likely than usual to cause regressions.
## Breaking changes
The only "breaking" change is adding a field to `Style`. Probably
doesn't bear mentioning?
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Contributes to #15460
## Solution
- Added two new features, `std` (default) and `alloc`, gating `std` and
`alloc` behind them respectively.
- Added missing `f32` functions to `std_ops` as required. These `f32`
methods have been added to the `clippy.toml` deny list to aid in
`no_std` development.
## Testing
- CI
- `cargo clippy -p bevy_math --no-default-features --features libm
--target "x86_64-unknown-none"`
- `cargo test -p bevy_math --no-default-features --features libm`
- `cargo test -p bevy_math --no-default-features --features "libm,
alloc"`
- `cargo test -p bevy_math --no-default-features --features "libm,
alloc, std"`
- `cargo test -p bevy_math --no-default-features --features "std"`
## Notes
The following items require the `alloc` feature to be enabled:
- `CubicBSpline`
- `CubicBezier`
- `CubicCardinalSpline`
- `CubicCurve`
- `CubicGenerator`
- `CubicHermite`
- `CubicNurbs`
- `CyclicCubicGenerator`
- `RationalCurve`
- `RationalGenerator`
- `BoxedPolygon`
- `BoxedPolyline2d`
- `BoxedPolyline3d`
- `SampleCurve`
- `SampleAutoCurve`
- `UnevenSampleCurve`
- `UnevenSampleAutoCurve`
- `EvenCore`
- `UnevenCore`
- `ChunkedUnevenCore`
This requirement could be relaxed in certain cases, but I had erred on
the side of gating rather than modifying. Since `no_std` is a new set of
platforms we are adding support to, and the `alloc` feature is enabled
by default, this is not a breaking change.
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
Co-authored-by: Matty <2975848+mweatherley@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
~Blocked on #13417~
Motivation is the same as in #13417. If users can sort `QueryIter`, to
only makes sense to also allow them to use this functionality on
`QueryManyIter`.
## Solution
Also implement the sorts on `QueryManyIter`.
The implementation of the sorts themselves are mostly the same as with
`QueryIter` in #13417.
They differ in that they re-use the `entity_iter` passed to the
`iter_many`, and internally call `iter_many_unchecked_manual` on the
lens `QueryState` with it.
These methods also return a different struct, `QuerySortedManyIter`,
because there is no longer a guarantee of unique entities.
`QuerySortedManyIter` implements the various `Iterator` traits for
read-only iteration, as `QueryManyIter` does + `DoubleEndedIterator`.
For mutable iteration, there is both a `fetch_next` and a
`fetch_next_back` method. However, they only become available after the
user calls `collect_inner` on `QuerySortedManyIter` first. This collects
the inner `entity_iter` (this is the sorted one, **not** the original
the user passed) to drop all query lens items to avoid aliasing.
When TAITs are available this `collect_inner` could be hidden away,
until then it is unfortunately not possible to elide this without either
regressing read-only iteration, or introducing a whole new type, mostly
being a copy of `QuerySortedIter`.
As a follow-up we could add a `entities_all_unique` method to check
whether the entity list consists of only unique entities, and then
return a `QuerySortedIter` from it (under opaque impl Trait if need be),
*allowing mutable `Iterator` trait iteration* over what was originally
an `iter_many` call.
Such a method can also be added to `QueryManyIter`, albeit needing a
separate, new return type.
## Testing
I've switched the third example/doc test under `sort` out for one that
shows the collect_inner/fetch_next_back functionality, otherwise the
examples are the same as in #13417, adjusted to use `iter_many` instead
of `iter`.
The `query-iter-many-sorts` test checks for equivalence to the
underlying sorts.
The test after shows that these sorts *do not* panic after
`fetch`/`fetch_next` calls.
## Changelog
Added `sort`, `sort_unstable`, `sort_by`, `sort_unstable_by`,
`sort_by_key`, `sort_by_cached_key` to `QueryManyIter`.
Added `QuerySortedManyIter`.
# Objective
- dont depend on wgpu if we dont have to
## Solution
- works towards this, but doesnt fully accomplish it. the remaining
types stopping us from doing this need to be moved upstream, i will PR
this
## Testing
- 3d_scene runs
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
Add support for multiple box shadows on a single `Node`.
## Solution
* Rename `BoxShadow` to `ShadowStyle` and remove its `Component` derive.
* Create a new `BoxShadow` component that newtypes a `Vec<ShadowStyle>`.
* Add a `new` constructor method to `BoxShadow` for single shadows.
* Change `extract_shadows` to iterate through a list of shadows per
node.
Render order is determined implicitly from the order of the shadows
stored in the `BoxShadow` component, back-to-front.
Might be more efficient to use a `SmallVec<[ShadowStyle; 1]>` for the
list of shadows but not sure if the extra friction is worth it.
## Testing
Added a node with four differently coloured shadows to the `box_shadow`
example.
---
## Showcase
```
cargo run --example box_shadow
```
<img width="460" alt="four-shadow"
src="https://github.com/user-attachments/assets/2f728c47-33b4-42e1-96ba-28a774b94b24">
## Migration Guide
Bevy UI now supports multiple shadows per node. A new struct
`ShadowStyle` is used to set the style for each shadow. And the
`BoxShadow` component is changed to a tuple struct wrapping a vector
containing a list of `ShadowStyle`s. To spawn a node with a single
shadow you can use the `new` constructor function:
```rust
commands.spawn((
Node::default(),
BoxShadow::new(
Color::BLACK.with_alpha(0.8),
Val::Percent(offset.x),
Val::Percent(offset.y),
Val::Percent(spread),
Val::Px(blur),
)
));
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Fixes: #15663
## Solution
- Add an `is_forward_plane` method to `Aabb`, and a `contains_aabb`
method to `Frustum`.
## Test
- I have created a frustum with an offset along with three unit tests to
evaluate the `contains_aabb` algorithm.
## Explanation for the Test Cases
- To facilitate the code review, I will explain how the frustum is
created. Initially, we create a frustum without any offset and then
create a cuboid that is just contained within it.
<img width="714" alt="image"
src="https://github.com/user-attachments/assets/a9ac53a2-f8a3-4e09-b20b-4ee71b27a099">
- Secondly, we move the cuboid by 2 units along both the x-axis and the
y-axis to make it more general.
## Reference
- [Frustum
Culling](https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling#)
- [AABB Plane
intersection](https://gdbooks.gitbooks.io/3dcollisions/content/Chapter2/static_aabb_plane.html)
---------
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
# Objective
- I got tired of calling `enable_state_scoped_entities`, and though it
would make more sense to define that at the place where the state is
defined
## Solution
- add a derive attribute `#[states(scoped_entities)]` when derive
`States` or `SubStates` that enables it automatically when adding the
state
## Testing
- Ran the examples using it, they still work
# Objective
There is currently no way of getting `QueryState` from `&World`, so it
is hard to, for example, iterate over all entities with a component,
only having `&World`.
## Solution
Add `try_new` function to `QueryState` that internally uses
`WorldQuery`'s `get_state`.
## Testing
No testing
# Objective
Combine the `Option<_>` state in `FunctionSystem` into a single `Option`
to provide clarity and save space.
## Solution
Simplifies `FunctionSystem`'s layout by using a single
`Option<FunctionSystemState>` for state that must be initialized before
running, and saves a byte by removing the need to store an enum tag.
Additionally, calling `System::run` on an uninitialized `System` will
now give a more descriptive message prior to verifying the `WorldId`.
## Testing
Ran CI checks locally.
# Objective
See title.
## Solution
Move `bevy_animation` import to where it is used.
## Testing
Compiled with and without `bevy_animation` feature enabled.
# Objective
- Avoid recreating the monitor every loop (temp fix until it's done
properly on winit side)
- Add a new `WinitSettings` preset for mobile that makes the winit loop
wait more and recommend its usage
Co-authored by: @BenjaminBrienen
# Objective
Fixes#16494. Closes#16539, which this replaces. Suggestions alone
weren't enough, so now we have a new PR!
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
- In 0.14, ZIndex and GlobalZIndex where split from a shared enum into
separate components. There have been a few people confused by the
behavior of ZIndex when they really needed GlobalZIndex.
## Solution
- Update ZIndex docs to improve discoverability of GlobalZIndex.
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# Objective
Fixes#16531
I also added change detection when creating the pipeline, which
technically isn't needed but it felt weird leaving it as is.
## Solution
Remove the pipeline if CAS is disabled. The uniform was already being
removed, which caused flickering / weirdness.
## Testing
Tested the anti_alias example by toggling CAS a bunch on/off.
# Objective
Animating component fields requires too much boilerplate at the moment:
```rust
#[derive(Reflect)]
struct FontSizeProperty;
impl AnimatableProperty for FontSizeProperty {
type Component = TextFont;
type Property = f32;
fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property> {
Some(&mut component.font_size)
}
}
animation_clip.add_curve_to_target(
animation_target_id,
AnimatableKeyframeCurve::new(
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
.into_iter()
.zip([24.0, 80.0, 24.0, 80.0, 24.0, 80.0, 24.0]),
)
.map(AnimatableCurve::<FontSizeProperty, _>::from_curve)
.expect("should be able to build translation curve because we pass in valid samples"),
);
```
## Solution
This adds `AnimatedField` and an `animated_field!` macro, enabling the
following:
```rust
animation_clip.add_curve_to_target(
animation_target_id,
AnimatableCurve::new(
animated_field!(TextFont::font_size),
AnimatableKeyframeCurve::new(
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0]
.into_iter()
.zip([24.0, 80.0, 24.0, 80.0, 24.0, 80.0, 24.0]),
)
.expect(
"should be able to build translation curve because we pass in valid samples",
),
),
);
```
This required reworking the internals a bit, namely stripping out a lot
of the `Reflect` usage, as that implementation was fundamentally
incompatible with the `AnimatedField` pattern. `Reflect` was being used
in this context just to downcast traits. But we can get downcasting
behavior without the `Reflect` requirement by implementing `Downcast`
for `AnimationCurveEvaluator`.
This also reworks "evaluator identity" to support either a (Component /
Field) pair, or a TypeId. This allows properties to reuse evaluators,
even if they have different accessor methods. The "contract" here is
that for a given (Component / Field) pair, the accessor will return the
same value. Fields are identified by their Reflect-ed field index. The
(TypeId, usize) is prehashed and cached to optimize for lookup speed.
This removes the built-in hard-coded TranslationCurve / RotationCurve /
ScaleCurve in favor of AnimatableField.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The documentation for `bevy_app::App.world()` (and its mut variant)
could confuse some into thinking that this is the only World that the
App will contain.
## Solution
Clarify the documentation for `bevy_app::App.world()` (and its mut
variant), to say that it returns the main subapp's world. This helps
imply that Apps can contain more than one world (albeit, only one per
SubApp).
## Testing
This is a documentation change, with no changes to doctests. Thus,
testing is not necessary beyond ensuring the link syntax is correct.
# Objective
Fixes#16521
## Solution
If an empty span is encountered (such as the default `Text` value), we
skip it entirely when updating buffers. This prevents unnecessarily
bailing when the font doesn't exist (ex: when the default font is
disabled)
This reverts commit 3476a9f3a658fe7c8326ca0e618ad543914ca7f4.
# Objective
#16517 makes it impossible to select a libc version, now that the
"breaking" libc release was yanked
## Solution
Revert the version bump so we can select a version of sysinfo that
builds (the previous version)
# Objective
- Fixes#16363
- Ensure that someone using minimum version doesn't get the bugs that
were fixed in the 23.0.1 patch
## Solution
- Use wgpu 23.0.1
# Objective
In the [*Similar parameters* section of
`Query`](https://dev-docs.bevyengine.org/bevy/ecs/prelude/struct.Query.html#similar-parameters),
the doc link for `Single` actually links to `Query::single`, and
`Option<Single>` just links to `Option`. They should both link to
`Single`!
The first link is broken because there is a reference-style link defined
for `single`, but not for `Single`, and rustdoc treats the link as
case-insensitive for some reason.
## Solution
Fix the links!
## Testing
I built the docs locally with `cargo doc` and tested the links.
# Objective
- Refactor
## Solution
- Refactor
## Testing
- Ran 3d_scene
---
## Migration Guide
`RenderCreation::Manual` variant fields are now wrapped in a struct
called `RenderResources`
# Objective
`TemporaryRenderEntity` currently uses `SparseSet` storage, but doesn't
seem to fit the criteria for a component that would benefit from this.
Typical usage of `TemporaryRenderEntity` (and all current usages of it
in engine as far as I can tell) would be to spawn an entity with it once
and then iterate over it once to despawn that entity.
`SparseSet` is said to be useful for insert/removal perf at the cost of
iteration perf.
## Solution
Use the default table storage
## Testing
Possibly this could show up in stress tests like `many_buttons`. I
didn't do any benchmarking.
# Objective
When using a rect for a ui image, its content size is still equal to the
size of the full image instead of the size of the rect.
## Solution
Use the rect size if it is present.
## Testing
I tested it using all 4 possible combinations of having a rect and
texture atlas or not. See the showcase section.
---
## Showcase
<details>
<summary>Click to view showcase</summary>
```rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_systems(Startup, create_ui)
.run();
}
fn create_ui(
mut commands: Commands,
assets: Res<AssetServer>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
mut ui_scale: ResMut<UiScale>,
) {
let texture = assets.load("textures/fantasy_ui_borders/numbered_slices.png");
let layout = TextureAtlasLayout::from_grid(UVec2::splat(16), 3, 3, None, None);
let texture_atlas_layout = texture_atlas_layouts.add(layout);
ui_scale.0 = 2.;
commands.spawn(Camera2d::default());
commands
.spawn(Node {
display: Display::Flex,
align_items: AlignItems::Center,
..default()
})
.with_children(|parent| {
// nothing
parent.spawn(ImageNode::new(texture.clone()));
// with rect
parent.spawn(ImageNode::new(texture.clone()).with_rect(Rect::new(0., 0., 16., 16.)));
// with rect and texture atlas
parent.spawn(
ImageNode::from_atlas_image(
texture.clone(),
TextureAtlas {
layout: texture_atlas_layout.clone(),
index: 1,
},
)
.with_rect(Rect::new(0., 0., 8., 8.)),
);
// with texture atlas
parent.spawn(ImageNode::from_atlas_image(
texture.clone(),
TextureAtlas {
layout: texture_atlas_layout.clone(),
index: 2,
},
));
});
}
```
Before this change:
<img width="529" alt="Screenshot 2024-11-21 at 11 55 45"
src="https://github.com/user-attachments/assets/23196003-08ca-4049-8409-fe349bd5aa54">
After the change:
<img width="400" alt="Screenshot 2024-11-21 at 11 54 54"
src="https://github.com/user-attachments/assets/e2cd6ebf-859c-40a1-9fc4-43bb28b024e5">
</details>
# Objective
Original motivation was a bundle I am migrating that is `Copy` which
needs to be synced to the render world. It probably doesn't actually
*need* to be `Copy`, so this isn't critical or anything.
I am continuing to use this bundle while bundles still exist to give
users an easier migration path.
## Solution
These ZSTs might as well be `Copy`. Add `Copy` derives.
PR #15164 made Bevy consider the center of the mesh to be the center of
the axis-aligned bounding box (AABB). Unfortunately, this breaks
crossfading in many cases. LODs may have different AABBs and so the
center of the AABB may differ for different LODs of the same mesh. The
crossfading, however, relies on all LODs having *precisely* the same
position.
To address this problem, this PR adds a new field, `use_aabb`, to
`VisibilityRange`, which makes the AABB center point behavior opt-in.
@BenjaminBrienen first noticed this issue when reviewing PR #16286. That
PR contains a video showing the effects of this regression on the
`visibility_range` example. This commit fixes that example.
## Migration Guide
* The `VisibilityRange` component now has an extra field, `use_aabb`.
Generally, you can safely set it to false.
We have an early-out to avoid updating `RenderVisibilityRanges` when a
`VisibilityRange` component is *modified*, but not when one is
*removed*. This means that removing `VisibilityRange` from an entity
might not update the rendering.
This PR fixes the issue by adding a check for removed
`VisibilityRange`s.
# Objective
- Fixes#16472.
## Solution
- Add flags to `SpritePlugin` and `UiPlugin` to disable their picking
backends.
## Testing
- The change is pretty trivial, so not much to test!
---
## Migration Guide
- `UiPlugin` now contains an extra `add_picking` field if
`bevy_ui_picking_backend` is enabled.
- `SpritePlugin` is no longer a unit struct, and has one field if
`bevy_sprite_picking_backend` is enabled (otherwise no fields).
# Objective
- Fixes#16469.
## Solution
- Make the picking backend features not enabled by default in each
sub-crate.
- Make features in `bevy_internal` to set the backend features
- Make the root `bevy` crate set the features by default.
## Testing
- The mesh and sprite picking examples still work correctly.
I'm not sure why, but somehow `#[derive(Reflect)]` on a tuple struct
with a boxed trait object can result in linker errors when dynamic
linking is used on Windows using `rust-lld`:
```
= note: rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..reflect..PartialReflect$u20$for$u20$bevy_animation..AnimationEventFn$GT$::reflect_partial_eq::hc4cce1dc55e42e0b␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..from_reflect..FromReflect$u20$for$u20$bevy_animation..AnimationEventFn$GT$::from_reflect::hc2b1d575b8491092␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..tuple_struct..TupleStruct$u20$for$u20$bevy_animation..AnimationEventFn$GT$::clone_dynamic::hab42a4edc8d6b5c2␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..tuple_struct..TupleStruct$u20$for$u20$bevy_animation..AnimationEventFn$GT$::field::h729a3d6dd6a27a43␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..tuple_struct..TupleStruct$u20$for$u20$bevy_animation..AnimationEventFn$GT$::field_mut::hde1c34846d77344b␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..type_registry..GetTypeRegistration$u20$for$u20$bevy_animation..AnimationEventFn$GT$::get_type_registration::hb96eb543e403a132␍
rust-lld: error: <root>: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..type_registry..GetTypeRegistration$u20$for$u20$bevy_animation..AnimationEventFn$GT$::register_type_dependencies::hcf1a4b69bcfea6ae␍
rust-lld: error: undefined symbol: bevy_animation::_::_$LT$impl$u20$bevy_reflect..reflect..PartialReflect$u20$for$u20$bevy_animation..AnimationEventFn$GT$::reflect_partial_eq::hc4cce1dc55e42e0b␍
```
etc.
Adding `#[reflect(opaque)]` to the `Reflect` derive fixes the problem,
and that's what this patch does. I think that adding
`#[reflect(opaque)]` is harmless, as there's little that reflection
allows with a boxed trait object anyhow.
# Objective
- Fixes#16406 even more. The previous implementation did not take into
account the depth of the requiree when setting the depth relative to the
required_by component.
## Solution
- Add the depth of the requiree!
## Testing
- Added a test.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
We switch back and forwards between logical and physical coordinates all
over the place. Systems have to query for cameras and the UiScale when
they shouldn't need to. It's confusing and fragile and new scale factor
bugs get found constantly.
## Solution
* Use physical coordinates whereever possible in `bevy_ui`.
* Store physical coords in `ComputedNode` and tear out all the unneeded
scale factor calculations and queries.
* Add an `inverse_scale_factor` field to `ComputedNode` and set nodes
changed when their scale factor changes.
## Migration Guide
`ComputedNode`'s fields and methods now use physical coordinates.
`ComputedNode` has a new field `inverse_scale_factor`. Multiplying the
physical coordinates by the `inverse_scale_factor` will give the logical
values.
---------
Co-authored-by: atlv <email@atlasdostal.com>
# Objective
Needing to derive `AnimationEvent` for `Event` is unnecessary, and the
trigger logic coupled to it feels like we're coupling "event producer"
logic with the event itself, which feels wrong. It also comes with a
bunch of complexity, which is again unnecessary. We can have the
flexibility of "custom animation event trigger logic" without this
coupling and complexity.
The current `animation_events` example is also needlessly complicated,
due to it needing to work around system ordering issues. The docs
describing it are also slightly wrong. We can make this all a non-issue
by solving the underlying ordering problem.
Related to this, we use the `bevy_animation::Animation` system set to
solve PostUpdate animation order-of-operations issues. If we move this
to bevy_app as part of our "core schedule", we can cut out needless
`bevy_animation` crate dependencies in these instances.
## Solution
- Remove `AnimationEvent`, the derive, and all other infrastructure
associated with it (such as the `bevy_animation/derive` crate)
- Replace all instances of `AnimationEvent` traits with `Event + Clone`
- Store and use functions for custom animation trigger logic (ex:
`clip.add_event_fn()`). For "normal" cases users dont need to think
about this and should use the simpler `clip.add_event()`
- Run the `Animation` system set _before_ updating text
- Move `bevy_animation::Animation` to `bevy_app::Animation`. Remove
unnecessary `bevy_animation` dependency from `bevy_ui`
- Adjust `animation_events` example to use the simpler `clip.add_event`
API, as the workarounds are no longer necessary
This is polishing work that will land in 0.15, and I think it is simple
enough and valuable enough to land in 0.15 with it, in the interest of
making the feature as compelling as possible.
# Objective
A new user is likely to try `Query<Component>` instead of
`Query<&Component>`. The error message should guide them to the right
solution.
## Solution
Add a note to the on_unimplemented message for `QueryData` recommending
`&T` and `&mut T`.
The full error message now looks like:
```
error[E0277]: `A` is not valid to request as data in a `Query`
--> crates\bevy_ecs\src\query\world_query.rs:260:18
|
260 | fn system(query: Query<A>) {}
| ^^^^^^^^ invalid `Query` data
|
= help: the trait `fetch::QueryData` is not implemented for `A`
= note: if `A` is a component type, try using `&A` or `&mut A`
= help: the following other types implement trait `fetch::QueryData`:
&'__w mut T
&Archetype
&T
()
(F,)
(F0, F1)
(F0, F1, F2)
(F0, F1, F2, F3)
and 41 others
note: required by a bound in `system::query::Query`
--> crates\bevy_ecs\src\system\query.rs:362:37
|
362 | pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> {
| ^^^^^^^^^ required by this bound in `Query`
```
Alternative to #16450
# Objective
detailed_trace! in its current form does not work (and breaks CI)
## Solution
Fix detailed_trace by checking for the feature properly, adding it to
the correct crates, and removing it from the incorrect crates
# Objective
- Fixes#16406
- Fixes an issue where registering a "deeper" required component, then a
"shallower" required component, would result in the wrong required
constructor being used for the root component.
## Solution
- Make `register_required_components` add any "parent" of a component as
`required_by` to the new "child".
- Assign the depth of the `requiree` plus 1 as the depth of a new
runtime required component.
## Testing
- Added two new tests.
# Objective
- Add methods to facilitate `TextFont` component creation and insertion.
## Solution
- Added `from_font` and `from_font_size` which return a new `TextFont`
with said attributes provided as parameters.
- Added `with_font` and `with_font_size` which return an existing
`TextFont` modifying said attributes with the values provided as
parameters.
## Testing
- CI Checks.
- Tested methods locally by changing values and running the `text_debug`
example.
# Objective
Run this without this PR:
`cargo build -p bevy_hierarchy --no-default-features`
You'll get:
```
error[E0432]: unresolved import `bevy_reflect`
--> crates/bevy_hierarchy/src/events.rs:2:5
|
2 | use bevy_reflect::Reflect;
| ^^^^^^^^^^^^ use of undeclared crate or module `bevy_reflect`
For more information about this error, try `rustc --explain E0432`.
error: could not compile `bevy_hierarchy` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
```
Because of this line:
```rs
use bevy_reflect::Reflect;
#[derive(Event, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "reflect", derive(Reflect), reflect(Debug, PartialEq))]
pub enum HierarchyEvent { .. }
```
## Solution
use FQN: `derive(bevy_reflect::Reflect)`
## Testing
`cargo build -p bevy_hierarchy --no-default-features`
# Objective
It looks like this file was created based on the `ui_texture_slice`
rendering code and some variable names weren't updated.
## Solution
Rename "texture slice" variable names to "box shadow".
# Objective
#16222 regressed the user experience of actually using gamepads:
```rust
// Before 16222
gamepad.just_pressed(GamepadButton::South)
// After 16222
gamepad.digital.just_pressed(GamepadButton::South)
// Before 16222
gamepad.get(GamepadButton::RightTrigger2)
// After 16222
gamepad.analog.get(GamepadButton::RighTrigger2)
```
Users shouldn't need to think about "digital vs analog" when checking if
a button is pressed. This abstraction was intentional and I strongly
believe it is in our users' best interest. Buttons and Axes are _both_
digital and analog, and this is largely an implementation detail. I
don't think reverting this will be controversial.
## Solution
- Revert most of #16222
- Add the `Into<T>` from #16222 to the internals
- Expose read/write `digital` and `analog` accessors on gamepad, in the
interest of enabling the mocking scenarios covered in #16222 (and
allowing the minority of users that care about the "digital" vs "analog"
distinction in this context to make that distinction)
---------
Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
- bevy_render (poorly) implements gcd (which should be in bevy_math but
theres not enough justification to have it there either anyways cus its
just one usage)
## Solution
- hardcoded LUT replacement for the one usage
## Testing
- verified the alternative implementation of 4/gcd(4,x) agreed with
original for 0..200
# Objective
https://github.com/AccessKit/accesskit/pull/475 changed how text content
should be set for AccessKit nodes with a role of `Label`. This was
unfortunately missing from #16234.
## Solution
When building an `accesskit::Node` with `Role::Label`, calls `set_value`
instead of `set_label` on the node to set its content.
## Testing
I can't test this right now on my Windows machine due to a compilation
error with wgpu-hal I have no idea how to resolve.
**NOTE: This is based on, and should be merged alongside,
https://github.com/bevyengine/bevy/pull/15482.** I'll leave this in
draft until that PR is merged.
# Objective
Equivalent of https://github.com/bevyengine/bevy/pull/15482 but for
serialization. See that issue for the motivation.
Also part of this tracking issue:
https://github.com/bevyengine/bevy/issues/15518
This PR is non-breaking, just like the deserializer PR (because the new
type parameter `P` has a default `P = ()`).
## Solution
Identical solution to the deserializer PR.
## Testing
Added unit tests and a very comprehensive doc test outlining a clear
example and use case.
# Objective
Fixes#16406.
Currently, the `#[require(...)]` attribute internally registers
component requirements using `register_required_components_manual`. This
is done recursively in a way where every requirement in the "inheritance
tree" is added into a flat `RequiredComponents` hash map with component
constructors and inheritance depths stored.
However, this does not consider runtime requirements: if a plugins has
already registered `C` as required by `B`, and a component `A` requires
`B` through the macro attribute, spawning an entity with `A` won't add
`C`. The `required_by` hash set for `C` doesn't have `A`, and the
`RequiredComponents` of `A` don't have `C`.
Intuitively, I would've thought that the macro attribute's requirements
were always added *before* runtime requirements, and in that case I
believe this shouldn't have been an issue. But the macro requirements
are based on `Component::register_required_components`, which in a lot
of cases (I think) is only called *after* the first time a bundle with
the component is inserted. So if a runtime requirement is defined
*before* this (as is often the case, during `Plugin::build`), the macro
may not take it into account.
## Solution
Register requirements inherited from the `required` component in
`register_required_components_manual_unchecked`.
## Testing
I added a test, essentially the same as in #16406, and it now passes. I
also ran some of the tests in #16409, and they seem to work as expected.
All the existing tests for required components pass.
# Objective
Seemed to have missed the export of `DynamicComponentFetch` from #15593.
`TryFromFilteredError` which is returned by `impl
TryFrom<FiliteredEntityMut/Ref> for EntityRef/Mut` also seemed to have
been missing.
## Solution
Export both of them.
# Objective
MSRV in the standalone crates should be accurate
## Solution
Determine the msrv of each crate and set it
## Testing
Adding better msrv checks to the CI is a next-step.
# Objective
- Fix part of #15920
## Solution
- Keep track of the last written amount of bytes, and bind only that
much of the buffer.
## Testing
- Did you test these changes? If so, how? No
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
---
## Migration Guide
- Fixed a bug with StorageBuffer and DynamicStorageBuffer binding data
from the previous frame(s) due to caching GPU buffers between frames.
# Objective
When adding custom BRP methods one might need to:
- Run custom systems in the `RemoteLast` schedule.
- Order those systems before/after request processing and cleanup.
For example in `bevy_remote_inspector` we need a way to perform some
preparation _before_ request processing. And to perform cleanup
_between_ request processing and watcher cleanup.
## Solution
- Make `RemoteLast` public
- Add `RemoteSet` with `ProcessRequests` and `Cleanup` variants.
I didn't mean to make this item private, fixing it for the 0.15 release
to be consistent with 0.14.
(maintainers: please make sure this gets merged into the 0.15 release
branch as well as main)
# Objective
- Fixes#16152
## Solution
- Put `bevy_window` and `bevy_a11y` behind the `bevy_window` feature.
they were the only difference
- Add `ScheduleRunnerPlugin` to the `DefaultPlugins` when `bevy_window`
is disabled
- Remove `HeadlessPlugins`
- Update the `headless` example
# Objective
- Fixes#16285
- Inactive camera are keeping the component `ViewUniformOffset` from
when they were active, still matching some queries trying to render to
them
## Solution
- Remove component `ViewUniformOffset` from cameras that are inactive
## Testing
- Ran example `render_primitives` and switched camera
Tweaks picking docs slightly for formatting and to add additional
context about the ordering of `Over` and `Out` events. Also shifts `Out`
to trigger before `Over` in the global event ordering.
Because of how focus is tracked, we must send all `Over` and `Out`
events at the same time, in a block. Originally I had `Over` precede
`Out` in the global event order, because this seemed natural. However,
the effect of this, when a pointer moves between entities, is to have
the new entity receive `Over` before the old entity received `Out`,
which several users found confusing.
The new ordering (out before over globally, over before out locally per
entity) should make it much easier to write hover state cleanup code.
# Objective
- When picking sprites, the pointer is offset from the mouse, causing
you to pick sprites you're not mousing over!
## Solution
- Shift over the cursor by the minimum of the viewport.
## Testing
- I was already using the bevy_mod_picking PR for my project, so it
seems to work!
- I tested this on the sprite_example (making the camera only render to
part of the viewport), and it also works there.
## Notes
- This is just https://github.com/aevyrie/bevy_mod_picking/pull/365 but
in Bevy form.
- We don't need to renormalize the viewport in any way since the
viewport is specified in pixels, so all that matters is that the origin
is correct.
Co-authored-by: johanhelsing <johanhelsing@gmail.com>
# Objective
PCSS still has some fundamental issues (#16155). We should resolve them
before "releasing" the feature.
## Solution
1. Rename the already-optional `pbr_pcss` cargo feature to
`experimental_pbr_pcss` to better communicate its state to developers.
2. Adjust the description of the `experimental_pbr_pcss` cargo feature
to better communicate its state to developers.
3. Gate PCSS-related light component fields behind that cargo feature,
to prevent surfacing them to developers by default.
# Objective
UI Anti-aliasing is incorrectly implemented. It always uses an edge
radius of 0.25 logical pixels, and ignores the physical resolution. For
low dpi screens 0.25 is is too low and on higher dpi screens the
physical edge radius is much too large, resulting in visual artifacts.
## Solution
Multiply the distance by the scale factor in the `antialias` function so
that the edge radius stays constant in physical pixels.
## Testing
To see the problem really clearly run the button example with `UiScale`
set really high. With `UiScale(25.)` on main if you examine the button's
border you can see a thick gradient fading away from the edges:
<img width="127" alt="edgg"
src="https://github.com/user-attachments/assets/7c852030-c0e8-4aef-8d3e-768cb2464cab">
With this PR the edges are sharp and smooth at all scale factors:
<img width="127" alt="edge"
src="https://github.com/user-attachments/assets/b3231140-1bbc-4a4f-a1d3-dde21f287988">
# Objective
Text2d doesn't respond to changes to the window scalefactor.
Fixes#16223
## Solution
In `update_text2d_layout` store the previous scale factor in a `Local`
instead and check against the current scale factor to detect changes.
It seems like previously the text wasn't updated because of a bug with
the `WindowScaleFactorChanged` event and it isn't emitted after changes
to the scale factor. That needs to be looked into, but this will work
for now.
## Testing
Really simple app that draws a big message in the middle of the window:
```
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
Text2d::new("Hello"),
TextFont {
font_size: 400.,
..Default::default()
},
));
}
```
Looks fine:
<img width="500" alt="hello1"
src="https://github.com/user-attachments/assets/5320746b-687e-4682-9e4c-bc43ab7ff9d3">
On main, after changing the monitor's scale factor:
<img width="500" alt="hello2"
src="https://github.com/user-attachments/assets/486cea16-fc44-4d66-9468-6f68905d4196">
With this PR the text maintains the same size and position after the
scale factor is changed.
# Objective
- Describe the objective or issue this PR addresses.
Use the fully qualified name for `Component` in the `require` attribute
- If you're fixing a specific issue, say "Fixes #X".
Fixes#16377
## Solution
- Describe the solution used to achieve the objective above.
Use the fully qualified name for `Component` in the `require` attribute,
i.e.,`<#ident as #bevy_ecs_path::component::Component>`
## Testing
- Did you test these changes? If so, how?
`cargo run -p ci -- lints`
`cargo run -p ci -- compile`
`cargo run -p ci -- test`
- Are there any parts that need more testing?
no
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
try to compile
```rust
#[derive(::bevy::ecs::component::Component, Default)]
pub struct A;
#[derive(::bevy::ecs::component::Component)]
#[require(A)]
pub struct B;
```
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Mac only
---
</details>
## Migration Guide
> This section is optional. If there are no breaking changes, you can
delete this section.
- If this PR is a breaking change (relative to the last release of
Bevy), describe how a user might need to migrate their code to support
these changes
- Simply adding new functionality is not a breaking change.
- Fixing behavior that was definitely a bug, rather than a questionable
design choice is not a breaking change.
Co-authored-by: Volodymyr Enhelhardt <volodymyr.enhelhardt@ambr.net>
# Objective
We currently use special "floating" constructors for `EasingCurve`,
`FunctionCurve`, and `ConstantCurve` (ex: `easing_curve`). This erases
the type being created (and in general "what is happening"
structurally), for very minimal ergonomics improvements. With rare
exceptions, we prefer normal `X::new()` constructors over floating `x()`
constructors in Bevy. I don't think this use case merits special casing
here.
## Solution
Add `EasingCurve::new()`, use normal constructors everywhere, and remove
the floating constructors.
I think this should land in 0.15 in the interest of not breaking people
later.
# Objective
Fixes#16266
## Solution
Added an `UnregisterSystem` command struct and
`Commands::unregister_system`. Also renamed `World::remove_system` and
`World::remove_system_cached` to `World::unregister_*`
## Testing
It's a fairly simple change, but I tested locally to ensure it actually
works.
---------
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
# Objective
Fixes#16316
## Solution
Tweaked a few crates cargo files until I was able to build and test
`bevy_ui` via `cargo test --package bevy_ui`
## Testing
- ran `cargo test --package bevy_ui` successfully
- CI should catch anything amiss (Hopefully?)
# Objective
`ButtonBundle` has an `ImageNode` component (renamed from `UiImage`)
which wasn't a problem in 0.14 but in 0.15 `requires` pulls in the
`ContentSize` and `NodeImageSize` which means that by default
`ButtonBundle` nodes are given a measure func based on the size of the
image belonging to `TRANSPARENT_IMAGE_HANDLE`, which is 1x1.
This doesn't make sense and the behaviour for default image nodes should
either be to go to zero size or not add a measure func.
## Solution
Check if an image has a `TRANSPARENT_IMAGE_HANDLE` and if it does remove
its measure func.
Possibly a zero-sized measure would make more sense, but that would
break existing code.
## Testing
Used `ButtonBundle` in the 0.15 `button` example and the border doesn't
render, after this change it does.
# Objective
- Fix bug where `UiSurface::set_camera_children` (and
`UiSurface::update_children` sometimes) will panic if you remove and add
a `Node` component in a single tick. This is more likely to happen now
because of `remove_with_requires`.
## Solution
- Filter out entities with `Node` when cleaning up entities from
`RemovedComponents<Node>`.
## Testing
- Not tested (rust compiler refused to cooperate when I tried to patch
this into my project), correct by inspection.
# Objective
- Allow to configure `on_thread_spawn` and `on_thread_destroy` when
using `TaskPoolPlugin` of bevy.
## Solution
- In `TaskPoolThreadAssignmentPolicy`, two options `on_thread_spawn` and
`on_thread_destroy` are added, which will be passed to two new methods
motioned above when creating corresponding task pool using builder.
- Due to lack of debug derive for these two options, manually implement
the debug for `TaskPoolThreadAssignmentPolicy`.
---
## Changelog
### Added
- `on_thread_spawn` option and `on_thread_destroy` option to the
`TaskPoolPlugin`, allow user to customize them as needed.
## Migration Guide
- `TaskPooolThreadAssignmentPolicy` now has two additional fields:
`on_thread_spawn` and `on_thread_destroy`. Please consider defaulting
them to `None`.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
_If I understand it correctly_, we were checking mesh visibility, as
well as re-rendering point and spot light shadow maps for each view.
This makes it so that M views and N lights produce M x N complexity.
This PR aims to fix that, as well as introduce a stress test for this
specific scenario.
## Solution
- Keep track of what lights have already had mesh visibility calculated
and do not calculate it again;
- Reuse shadow depth textures and attachments across all views, and only
render shadow maps for the _first_ time a light is encountered on a
view;
- Directional lights remain unaltered, since their shadow map cascades
are view-dependent;
- Add a new `many_cameras_lights` stress test example to verify the
solution
## Showcase
110% speed up on the stress test
83% reduction of memory usage in stress test
### Before (5.35 FPS on stress test)
<img width="1392" alt="Screenshot 2024-09-11 at 12 25 57"
src="https://github.com/user-attachments/assets/136b0785-e9a4-44df-9a22-f99cc465e126">
### After (11.34 FPS on stress test)
<img width="1392" alt="Screenshot 2024-09-11 at 12 24 35"
src="https://github.com/user-attachments/assets/b8dd858f-5e19-467f-8344-2b46ca039630">
## Testing
- Did you test these changes? If so, how?
- On my game project where I have two cameras, and many shadow casting
lights I managed to get pretty much double the FPS.
- Also included a stress test, see the comparison above
- Are there any parts that need more testing?
- Yes, I would like help verifying that this fix is indeed correct, and
that we were really re-rendering the shadow maps by mistake and it's
indeed okay to not do that
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the `many_cameras_lights` example
- On the `main` branch, cherry pick the commit with the example (`git
cherry-pick --no-commit 1ed4ace01`) and run it
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- macOS
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
Should compile successfully with any combination of features
## Solution
Add the missing import on the right cfg.
## Testing
Tested building locally.
Fixes https://github.com/bevyengine/bevy/issues/16352
# Objective
Glam has some common and useful types and helpers that are not in the
prelude of `bevy_math`. This includes shorthand constructors like
`vec3`, or even `Vec3A`, the aligned version of `Vec3`.
```rust
// The "normal" way to create a 3D vector
let vec = Vec3::new(2.0, 1.0, -3.0);
// Shorthand version
let vec = vec3(2.0, 1.0, -3.0);
```
## Solution
Add the following types and methods to the prelude:
- `vec2`, `vec3`, `vec3a`, `vec4`
- `uvec2`, `uvec3`, `uvec4`
- `ivec2`, `ivec3`, `ivec4`
- `bvec2`, `bvec3`, `bvec3a`, `bvec4`, `bvec4a`
- `mat2`, `mat3`, `mat3a`, `mat4`
- `quat` (not sure if anyone uses this, but for consistency)
- `Vec3A`
- `BVec3A`, `BVec4A`
- `Mat3A`
I did not add the u16, i16, or f64 variants like `dvec2`, since there
are currently no existing types like those in the prelude.
The shorthand constructors are currently used a lot in some places in
Bevy, and not at all in others. In a follow-up, we might want to
consider if we have a preference for the shorthand, and make a PR to
change the codebase to use it more consistently.
# Objective
- Fixes: #15603
## Solution
- Add an unsafe `get_mut_by_id_unchecked` to `EntityMut` that borrows
&self instead of &mut self, thereby allowing access to multiple
components simultaneously.
## Testing
- a unit test function `get_mut_by_id_unchecked` was added.
---------
Co-authored-by: Mike <mike.hsu@gmail.com>
**NOTE: Also see https://github.com/bevyengine/bevy/pull/15548 for the
serializer equivalent**
# Objective
The current `ReflectDeserializer` and `TypedReflectDeserializer` use the
`TypeRegistration` and/or `ReflectDeserialize` of a given type in order
to determine how to deserialize a value of that type. However, there is
currently no way to statefully override deserialization of a given type
when using these two deserializers - that is, to have some local data in
the same scope as the `ReflectDeserializer`, and make use of that data
when deserializing.
The motivating use case for this came up when working on
[`bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes),
when loading an animation graph asset. The `AnimationGraph` stores
`Vec<Box<dyn NodeLike>>`s which we have to load in. Those `Box<dyn
NodeLike>`s may store `Handle`s to e.g. `Handle<AnimationClip>`. I want
to trigger a `load_context.load()` for that handle when it's loaded.
```rs
#[derive(Reflect)]
struct Animation {
clips: Vec<Handle<AnimationClip>>,
}
```
```rs
(
clips: [
"animation_clips/walk.animclip.ron",
"animation_clips/run.animclip.ron",
"animation_clips/jump.animclip.ron",
],
)
````
Currently, if this were deserialized from an asset loader, this would be
deserialized as a vec of `Handle::default()`s, which isn't useful since
we also need to `load_context.load()` those handles for them to be used.
With this processor field, a processor can detect when `Handle<T>`s are
being loaded, then actually load them in.
## Solution
```rs
trait ReflectDeserializerProcessor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>;
}
```
```diff
- pub struct ReflectDeserializer<'a> {
+ pub struct ReflectDeserializer<'a, P = ()> { // also for ReflectTypedDeserializer
registry: &'a TypeRegistry,
+ processor: Option<&'a mut P>,
}
```
```rs
impl<'a, P: ReflectDeserializerProcessor> ReflectDeserializer<'a, P> { // also for ReflectTypedDeserializer
pub fn with_processor(registry: &'a TypeRegistry, processor: &'a mut P) -> Self {
Self {
registry,
processor: Some(processor),
}
}
}
```
This does not touch the existing `fn new`s.
This `processor` field is also added to all internal visitor structs.
When `TypedReflectDeserializer` runs, it will first try to deserialize a
value of this type by passing the `TypeRegistration` and deserializer to
the processor, and fallback to the default logic. This processor runs
the earliest, and takes priority over all other deserialization logic.
## Testing
Added unit tests to `bevy_reflect::serde::de`. Also using almost exactly
the same implementation in [my fork of
`bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes).
## Migration Guide
(Since I added `P = ()`, I don't think this is actually a breaking
change anymore, but I'll leave this in)
`bevy_reflect`'s `ReflectDeserializer` and `TypedReflectDeserializer`
now take a `ReflectDeserializerProcessor` as the type parameter `P`,
which allows you to customize deserialization for specific types when
they are found. However, the rest of the API surface (`new`) remains the
same.
<details>
<summary>Original implementation</summary>
Add `ReflectDeserializerProcessor`:
```rs
struct ReflectDeserializerProcessor {
pub can_deserialize: Box<dyn FnMut(&TypeRegistration) -> bool + 'p>,
pub deserialize: Box<
dyn FnMut(
&TypeRegistration,
&mut dyn erased_serde::Deserializer,
) -> Result<Box<dyn PartialReflect>, erased_serde::Error>
+ 'p,
}
```
Along with `ReflectDeserializer::new_with_processor` and
`TypedReflectDeserializer::new_with_processor`. This does not touch the
public API of the existing `new` fns.
This is stored as an `Option<&mut ReflectDeserializerProcessor>` on the
deserializer and any of the private `-Visitor` structs, and when we
attempt to deserialize a value, we first pass it through this processor.
Also added a very comprehensive doc test to
`ReflectDeserializerProcessor`, which is actually a scaled down version
of the code for the `bevy_animation_graph` loader. This should give
users a good motivating example for when and why to use this feature.
### Why `Box<dyn ..>`?
When I originally implemented this, I added a type parameter to
`ReflectDeserializer` to determine the processor used, with `()` being
"no processor". However when using this, I kept running into rustc
errors where it failed to validate certain type bounds and led to
overflows. I then switched to a dynamic dispatch approach.
The dynamic dispatch should not be that expensive, nor should it be a
performance regression, since it's only used if there is `Some`
processor. (Note: I have not benchmarked this, I am just speculating.)
Also, it means that we don't infect the rest of the code with an extra
type parameter, which is nicer to maintain.
### Why the `'p` on `ReflectDeserializerProcessor<'p>`?
Without a lifetime here, the `Box`es would automatically become `Box<dyn
FnMut(..) + 'static>`. This makes them practically useless, since any
local data you would want to pass in must then be `'static`. In the
motivating example, you couldn't pass in that `&mut LoadContext` to the
function.
This means that the `'p` infects the rest of the Visitor types, but this
is acceptable IMO. This PR also elides the lifetimes in the `impl<'de>
Visitor<'de> for -Visitor` blocks where possible.
### Future possibilities
I think it's technically possible to turn the processor into a trait,
and make the deserializers generic over that trait. This would also open
the door to an API like:
```rs
type Seed;
fn seed_deserialize(&mut self, r: &TypeRegistration) -> Option<Self::Seed>;
fn deserialize(&mut self, r: &TypeRegistration, d: &mut dyn erased_serde::Deserializer, s: Self::Seed) -> ...;
```
A similar processor system should also be added to the serialization
side, but that's for another PR. Ideally, both PRs will be in the same
release, since one isn't very useful without the other.
## Testing
Added unit tests to `bevy_reflect::serde::de`. Also using almost exactly
the same implementation in [my fork of
`bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes).
## Migration Guide
`bevy_reflect`'s `ReflectDeserializer` and `TypedReflectDeserializer`
now take a second lifetime parameter `'p` for storing the
`ReflectDeserializerProcessor` field lifetimes. However, the rest of the
API surface (`new`) remains the same, so if you are not storing these
deserializers or referring to them with lifetimes, you should not have
to make any changes.
</details>
# Objective
`glam` has opted to rename `Vec2::angle_between` to `Vec2::angle_to`
because of the difference in semantics compared to `Vec3::angle_between`
and others which return an unsigned angle `[0, PI]` where
`Vec2::angle_between` returns a signed angle `[-PI, PI]`.
We should follow suit for `Rot2` in 0.15 to avoid further confusion.
Links:
-
https://github.com/bitshifter/glam-rs/issues/514#issuecomment-2143202294
- https://github.com/bitshifter/glam-rs/pull/524
## Migration Guide
`Rot2::angle_between` has been deprecated, use `Rot2::angle_to` instead,
the semantics of `Rot2::angle_between` will change in the future.
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
# Objective
Fixes#15940
## Solution
Remove the `pub use` and fix the compile errors.
Make `bevy_image` available as `bevy::image`.
## Testing
Feature Frenzy would be good here! Maybe I'll learn how to use it if I
have some time this weekend, or maybe a reviewer can use it.
## Migration Guide
Use `bevy_image` instead of `bevy_render::texture` items.
---------
Co-authored-by: chompaa <antony.m.3012@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Currently when you attempt to change the cursor_grab_mode it caches
the new value whether the cursor grab succeeded or failed. This change
handles the Result being returned by set_cursor_grab and changes the
cursor_grab_mode back to the cached version in case of an Error.
- Creates a way to handle #16237 and #16238
## Solution
- I changed the signature of winit_windows attempt_grab to return the
Result<(), ExternalError> that winit set_cursor_grab returns. The system
that calls attempt_grab now checks if there's an error returned, and if
there is it sets the grab_mode back to the cached version (similar to
what hit_test does a few lines down).
## Testing
- I tested using this system that previously would not correctly lock
the mouse on Ubuntu/x11
```
pub fn lock_mouse(mut primary_window: Query<&mut Window, With<PrimaryWindow>>) {
let window = &mut primary_window.single_mut();
if window.focused {
window.cursor_options.grab_mode = CursorGrabMode::Confined;
} else {
window.cursor_options.grab_mode = CursorGrabMode::None;
}
}
```
- I only tested on Ubuntu with x11
# Objective
Fixes#15928
## Solution
return Error instead of panic
## Testing
I don't know if we need to add a test for this. It is pretty
straightforward.
# Objective
- wgpu 0.20 made workgroup vars stop being zero-init by default. this
broke some applications (cough foresight cough) and now we workaround
it. wgpu exposes a compilation option that zero initializes workgroup
memory by default, but bevy does not expose it.
## Solution
- expose the compilation option wgpu gives us
## Testing
- ran examples: 3d_scene, compute_shader_game_of_life, gpu_readback,
lines, specialized_mesh_pipeline. they all work
- confirmed fix for our own problems
---
</details>
## Migration Guide
- add `zero_initialize_workgroup_memory: false,` to
`ComputePipelineDescriptor` or `RenderPipelineDescriptor` structs to
preserve 0.14 functionality, add `zero_initialize_workgroup_memory:
true,` to restore bevy 0.13 functionality.
# Objective
- Fixes#16235
## Solution
- Both Bevy and AccessKit export a `Node` struct, to reduce confusion
Bevy will no longer re-export `AccessKit` from `bevy_a11y`
## Testing
- Tested locally
## Migration Guide
```diff
# main.rs
-- use bevy_a11y::{
-- accesskit::{Node, Rect, Role},
-- AccessibilityNode,
-- };
++ use bevy_a11y::AccessibilityNode;
++ use accesskit::{Node, Rect, Role};
# Cargo.toml
++ accesskit = "0.17"
```
- Users will need to add `accesskit = "0.17"` to the dependencies
section of their `Cargo.toml` file and update their `accesskit` use
statements to come directly from the external crate instead of
`bevy_a11y`.
- Make sure to keep the versions of `accesskit` aligned with the
versions Bevy uses.
# Objective
- Fixed issue where `thiserror` `#[error(...)]` attributes were
improperly converted to `derive_more` `#[display(...)]` equivalents in
certain cases with a tuple struct/enum variant.
## Solution
- Used `re/#\[display\(.*\{[0-9]+\}.*\)\]/` to find occurences of using
`{0}` where `{_0}` was intended (checked for other field indexes too)and
updated accordingly.
## Testing
- `cargo check`
- CI
## Notes
This was discovered by @dtolnay in [this
comment](https://github.com/bevyengine/bevy/pull/15772#discussion_r1833730555).
# Objective
`AudioPlayer::<AudioSource>(assets.load("audio.mp3"))` is awkward and
complicated to type because the `AudioSource` generic type cannot be
elided. This is especially annoying because `AudioSource` is used in the
majority of cases. Most users don't need to think about it.
## Solution
Add an `AudioPlayer::new()` function that is hard-coded to
`AudioSource`, allowing `AudioPlayer::new(assets.load("audio.mp3"))`.
Prefer using that in the relevant places.
# Objective
In the existing implementation, additive blending effectively treats the
node with least index specially by basically forcing its weight to be
`1.0` regardless of what its computed weight would be (based on the
weights in the `AnimationGraph` and `AnimationPlayer`).
Arguably this makes some amount of sense, because the "base" animation
is often one which was not authored to be used additively, meaning that
its sampled values are interpreted absolutely rather than as deltas.
However, this also leads to strange behavior with respect to animation
masks: if the "base" animation is masked out on some target, then the
next node is treated as the "base" animation, despite the fact that it
would normally be interpreted additively, and the weight of that
animation is thrown away as a result.
This is all kind of weird and revolves around special treatment (if the
behavior is even really intentional in the first place). From a
mathematical standpoint, there is nothing special about how the "base"
animation must be treated other than having a weight of 1.0 under an
`Add` node, which is something that the user can do without relying on
some bizarre corner-case behavior of the animation system — this is the
only present situation under which weights are discarded.
This PR changes this behavior so that the weight of every node is
incorporated. In other words, for an animation graph that looks like
this:
```text
┌───────────────┐
│Base clip ┼──┐
│ 0.5 │ │
└───────────────┘ │
┌───────────────┐ │ ┌───────────────┐ ┌────┐
│Additive clip 1┼──┼─►┤Additive blend ┼────►│Root│
│ 0.1 │ │ │ 1.0 │ └────┘
└───────────────┘ │ └───────────────┘
┌───────────────┐ │
│Additive clip 2┼──┘
│ 0.2 │
└───────────────┘
```
Previously, the result would have been
```text
base_clip + 0.1 * additive_clip_1 + 0.2 * additive_clip_2
```
whereas now it would be
```text
0.5 * base_clip + 0.1 * additive_clip_1 + 0.2 * additive_clip_2
```
and in the scenario where `base_clip` is masked out:
```text
additive_clip_1 + 0.2 * additive_clip_2
```
vs.
```text
0.1 * additive_clip_1 + 0.2 * additive_clip_2
```
## Solution
For background, the way that the additive blending procedure works is
something like this:
- During graph traversal, the node values and weights of the children
are pushed onto the evaluator `stack`. The traversal order guarantees
that the item with least node index will be on top.
- Once we reach the `Add` node itself, we start popping off the `stack`
and into the evaluator's `blend_register`, which is an accumulator
holding up to one weight-value pair:
- If the `blend_register` is empty, it is filled using data from the top
of the `stack`.
- Otherwise, the `blend_register` is combined with data popped from the
`stack` and updated.
In the example above, the additive blending steps would look like this
(with the pre-existing implementation):
1. The `blend_register` is empty, so we pop `(base_clip, 0.5)` from the
top of the `stack` and put it in. Now the value of the `blend_register`
is `(base_clip, 0.5)`.
2. The `blend_register` is non-empty: we pop `(additive_clip_1, 0.1)`
from the top of the `stack` and combine it additively with the value in
the `blend_register`, forming `(base_clip + 0.1 * additive_clip_1, 0.6)`
in the `blend_register` (the carried weight value goes unused).
3. The `blend_register` is non-empty: we pop `(additive_clip_2, 0.2)`
from the top of the `stack` and combine it additively with the value in
the `blend_register`, forming `(base_clip + 0.1 * additive_clip_1 + 0.2
* additive_clip_2, 0.8)` in the `blend_register`.
The solution in this PR changes step 1: the `base_clip` is multiplied by
its weight as it is added to the `blend_register` in the first place,
yielding `0.5 * base_clip + 0.1 * additive_clip_1 + 0.2 *
additive_clip_2` as the final result.
### Note for reviewers
It might be tempting to look at the code, which contains a segment that
looks like this:
```rust
if additive {
current_value = A::blend(
[
BlendInput {
weight: 1.0, // <--
value: current_value,
additive: true,
},
BlendInput {
weight: weight_to_blend,
value: value_to_blend,
additive: true,
},
]
.into_iter(),
);
}
```
and conclude that the explicit value of `1.0` is responsible for
overwriting the weight of the base animation. This is incorrect.
Rather, this additive blend has to be written this way because it is
multiplying the *existing value in the blend register* by 1 (i.e. not
doing anything) before adding the next value to it. Changing this to
another quantity (e.g. the existing weight) would cause the value in the
blend register to be spuriously multiplied down.
## Testing
Tested on `animation_masks` example. Checked `morph_weights` example as
well.
## Migration Guide
I will write a migration guide later if this change is not included in
0.15.
# Objective
After #12929 we no longer have methods to get component or ticks for
previously obtained table column.
It's possible to use a lower level API by indexing the slice, but then
it won't be possible to construct `ComponentTicks`.
## Solution
Make `ComponentTicks` fields public. They don't hold any invariants and
you can't get a mutable reference to the struct in Bevy.
I also removed the getters since they are no longer needed.
## Testing
- I tested the compilation
---
## Migration Guide
- Instead of using `ComponentTicks::last_changed_tick` and
`ComponentTicks::added_tick` methods, access fields directly.
# Objective
Re-enable some tests in `entity_ref.rs` that are marked as `#[ignore]`,
but that pass after #14561.
## Solution
Remove `#[ignore]` from those tests.
# Objective
Automatic imaging sizing for image nodes isn't working because the the
`ContentSize` requirement for `UiImage` got lost in some merge again.
Fixes#16239Fixes#16240
Fixes the missing images seen in #16241
## Solution
Require `ContentSize` for `UiImage`.
# Objective
- Fixes#16254
- fix building in wasm without custom_cursor
## Solution
- Properly flag `CustomCursor::Url` which only exist in wasm, but also
only when `custom_cursor` is enabled
## Testing
- `cargo check --target wasm32-unknown-unknown -p bevy_winit`
# Objective
- Attempts to fix#16042
## Solution
- Added a new `RemoteSystem` `SystemSet` for the BRP systems.
- Changed the schedule on which these systems run from `Update` to
`Last`.
## Testing
- I did not test these changes and would appreciate a hand in doing so.
I assume it would be good to test that you can order against these
systems easily now.
---
## Migration Guide
- `process_remote_requests`, `process_ongoing_watching_requests` and
`remove_closed_watching_requests` now run in the `Last` schedule. Make
sure you use `RemoteSystem` `SystemSet` in case you need to order your
systems against them.
# Objective
Addressing a suggestion I made in Discord: store gamepad name as a
`Name` component.
Advantages:
- Will be nicely displayed in inspector / editor.
- Easier to spawn in tests, just `world.spawn(Gamepad::default())`.
## Solution
`Gamepad` component now stores only vendor and product IDs and `Name`
stores the gamepad name.
Since `GamepadInfo` is no longer necessary, I removed it and merged its
fields into the connection event.
## Testing
- Run unit tests.
---
## Migration Guide
- `GamepadInfo` no longer exists:
- Name now accesible via `Name` component.
- Other information available on `Gamepad` component directly.
- `GamepadConnection::Connected` now stores all info fields directly.
# Objective
Use same pattern when creating `TransparentUi` items where the
`sort_key` is the `UiNode` stack index + some offset.
## Solution
Refactored to follow same pattern.
## Testing
Ran few UI examples.
## Doubts
Maybe `stack_z_offsets::BACKGROUND_COLOR` should be renamed. This is
used for `ExtractedUiNode`, which is not only used for "background
color" it's also used to render borders, images and text (I think).
In `bevy_mod_picking` events are driven by several interlocking state
machines, which read and write events, and share state in a few common
resources. When I merged theses state machines into one to make event
ordering work properly, I combined this state and hid it in a `Local`.
This PR exposes the state in a resource again. Also adds a simple little
API for it. Useful for adding debug UI.
# Objective
Exposes a means to create an asset directory (and its parent
directories). Wasn't sure whether we also wanted the variant to create
directories without the parent (i.e. `mkdir` instead of `mkdir -p`)?
Fixes https://github.com/bevyengine/bevy_editor_prototypes/issues/144
# Objective
- Bumps accesskit and accesskit_winit dependencies
## Solution
- Fixes several breaking API changes introduced in accesskit 0.23.
## Testing
- Tested with the ui example and seems to work comparably
# Objective
Closes#16221.
## Solution
- Make `Gamepad` fields public and remove delegates / getters.
- Move `impl Into` to `Axis` methods (delegates for `Axis` used `impl
Into` to allow passing both `GamepadAxis` and `GamepadButton`).
- Improve docs.
## Testing
- I run tests.
Not sure if the migration guide is needed, since it's a feature from RC,
but I wrote it just in case.
---
## Migration Guide
- `Gamepad` fields are now public.
- Instead of using `Gamepad` delegates like `Gamepad::just_pressed`,
call these methods directly on the fields.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>