Commit Graph

7238 Commits

Author SHA1 Message Date
atlv
a8bb208ed3
optimize ktx2 level data concatenation (#19845)
# Objective

- avoid several internal vec copies while collecting all the level data
in ktx2 load
- merge another little piece of #18411 (benchmarks there found this to
be a significant win)

## Solution

- reserve and extend

## Testing

- ran a few examples that load ktx2 images, like ssr. looks fine

## Future work

- fast path logic to skip the reading into different vecs and just read
it all in one go into the final buffer instead
- as above, but directly into gpu staging buffer perhaps
2025-06-29 21:59:56 +00:00
François Mockers
764be9199c
bevy_winit: fix compile and clippy on wasm (#19869)
# Objective

- bevy_winit has a warning when compiling without default feature on
linux
- bevy_winit has a clippy warning when compiling in wasm

## Solution

- Fix them

## Testing

```
cargo build -p bevy_winit --no-default-features --features winit/x11
cargo clippy --target wasm32-unknown-unknown -p bevy_winit --no-deps -- -D warnings
```
2025-06-29 21:30:28 +00:00
François Mockers
a98b5683ae
bevy_asset: fix clippy in wasm (#19865)
# Objective

- bevy_asset has a clippy warning in wasm:
[`clippy::io_other_error`](https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error)

```
error: this can be `std::io::Error::other(_)`
  --> crates/bevy_asset/src/io/wasm.rs:50:9
   |
50 |         std::io::Error::new(std::io::ErrorKind::Other, message)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error
   = note: `-D clippy::io-other-error` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(clippy::io_other_error)]`
help: use `std::io::Error::other`
   |
50 -         std::io::Error::new(std::io::ErrorKind::Other, message)
50 +         std::io::Error::other(message)
```

## Solution

- Fix it

## Testing

`cargo clippy --target wasm32-unknown-unknown -p bevy_asset --no-deps --
-D warnings`
2025-06-29 20:36:53 +00:00
JMS55
56710df934
bevy_solari ReSTIR DI (#19790)
# Objective

- Add temporal and spatial resampling to bevy_solari.

# Showcase
ReSTIR:

![image](https://github.com/user-attachments/assets/9b563713-d0cb-4f33-b402-dfa5a13ef3e2)

Previous RIS: 

![455750793-b70b968d-9c73-4983-9b6b-b60cace9b47a](https://github.com/user-attachments/assets/e62c852b-1f2c-4e86-ab35-a8058e9339d6)
2025-06-29 19:01:32 +00:00
atlv
ec1916a240
Dds transcode channel order fix (#19849)
# Objective

- Fix bug in dds channel order transcode
- taken from #18411

## Solution

- fix it
- improve docs a bit

## Testing

- example in linked pr
2025-06-29 18:19:05 +00:00
IceSentry
37aae00120
Add RenderStartup schedule to the RenderApp (#19841)
# Objective

- We sometimes want to spawn things on startup that only exist in the
RenderApp but right now there's no equivalent to the Startup schedule on
the RenderApp so we need to do all of that in the plugin build/finish
code

## Solution

- Add a RenderStartup schedule that runs on the RenderApp after the
plugins are initialized

## Testing

- I ported the custom_post_processing example to use this new schedule
and things worked as expected. I will push the change in a follow up PR
2025-06-29 18:14:10 +00:00
ickshonpe
e9daac4f11
Move TextShadow to text widget module (#19579)
# Objective

It's odd that `TextShadow` is accessible by importing `bevy::ui::*` but
`Text` isn't.

Move the `TextShadow` component to `text` widget module and move its
type registration to the `build_text_interop` function.
2025-06-29 17:37:04 +00:00
François Mockers
e6e731017d
bevy_input: build warnings without bevy_reflect (#19862)
# Objective

- bevy_input has build warnings when bevy_reflect isn't enabled

## Solution

- Fix them

## Testing

`cargo build -p bevy_input --no-default-features --features
bevy_math/libm`
2025-06-29 17:13:43 +00:00
François Mockers
c077c65ddd
bevy_utils: clippy without debug feature enabled (#19861)
# Objective

- bevy_utils has warnings with clippy

## Solution

- Fix them

## Testing

`cargo clippy -p bevy_utils  --no-deps -- -D warnings`
2025-06-29 17:13:27 +00:00
François Mockers
5f497efe90
bevy_platform: clippy without default features (#19860)
# Objective

- bevy_platform has clippy warnings when building without default
features

## Solution

- Fix them

## Testing

`cargo clippy -p bevy_platform --no-default-features --no-deps -- -D
warnings`
2025-06-29 17:12:57 +00:00
François Mockers
1fe559730c
bevy_ecs: remove use of needless_return (#19859)
# Objective

- bevy_ecs has a expected lint that is both needed and unneeded

## Solution

- Change the logic so that it's always not needed

## Testing

`cargo clippy -p bevy_ecs --no-default-features --no-deps -- -D
warnings`
2025-06-29 17:12:33 +00:00
François Mockers
8e12b1f0b2
bevy_ui compilation (#19858)
# Objective

- `bevy_ui` has errors and warnings when building independently

## Solution

- properly use the `bevy_ui_picking_backend` feature

## Testing

`cargo build -p bevy_ui`
2025-06-29 17:12:11 +00:00
Brian Reavis
795e273a9a
Don't create errors for ignored failed commands (#19718)
# Objective

1. Reduce overhead from error handling for ECS commands that
intentionally ignore errors, such as `try_despawn`. These commands
currently allocate error objects and pass them to a no-op handler
(`ignore`), which can impact performance when many operations fail.

2. Fix a hang when removing `ChildOf` components during entity
despawning. Excessive logging of these failures can cause significant
hangs (I'm noticing around 100ms).
    - Fixes https://github.com/bevyengine/bevy/issues/19777
    - Fixes https://github.com/bevyengine/bevy/issues/19753

<img width="1387" alt="image"
src="https://github.com/user-attachments/assets/5c67ab77-97bb-46e5-b287-2c502bef9358"
/>


## Solution

* Added a `ignore_error` method to the `HandleError` trait to use
instead of `handle_error_with(ignore)`. It swallows errors and does not
create error objects.
* Replaced `remove::<ChildOf>` with `try_remove::<ChildOf>` to suppress
expected (?) errors and reduce log noise.

## Testing

- I ran these changes on a local project.
2025-06-29 16:34:20 +00:00
Chris Russell
85448b767e
Make DebugName work when building with no default features (#19824)
# Objective

Let `bevy_utils` build with no default features.  

`cargo build -p bevy_utils --no-default-features` currently fails with 

```
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `alloc`
 --> crates\bevy_utils\src\debug_info.rs:1:5
  |
1 | use alloc::{borrow::Cow, fmt, string::String};
  |     ^^^^^ use of unresolved module or unlinked crate `alloc`
  |
  = help: add `extern crate alloc` to use the `alloc` crate

error[E0432]: unresolved import `alloc`
 --> crates\bevy_utils\src\debug_info.rs:1:5
  |
1 | use alloc::{borrow::Cow, fmt, string::String};
  |     ^^^^^ help: a similar path exists: `core::alloc`
```

I would have expected CI to catch this earlier, but I have not
investigated why it did not.

## Solution

Wrap the parts of `DebugName` that use `Cow` and `String` in
`cfg::alloc!`.

If the `debug` feature is enabled, then `DebugName` itself stores a
`Cow`, so make the `debug` feature require `bevy_platform/alloc`.

That is, you can use `DebugName` in no-std contexts when it's just a
ZST! (I bet it's even possible to support no-std `debug` by storing
`&'static str` instead of `Cow<'static, str>`, but that seemed like too
much complexity for now.)
2025-06-29 02:45:41 +00:00
atlv
57e58ef997
Meshlet BVH Culling (#19318)
# Objective

- Merge @SparkyPotato 's efforts to implement BVH-accelerated meshlet
culling.

## Solution

- Add hot reloading support
- Fix near-plane overculling
- Fix hzb sampling
- Fix orthographic error metric

## Testing

- Meshlet example, Nsight, hot-reloading and careful thinking

---------

Co-authored-by: SparkyPotato <noob.sparkypotato@gmail.com>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: charlotte <charlotte.c.mcelwain@gmail.com>
2025-06-29 00:04:21 +00:00
Talin
65bddbd3e4
Bevy Feathers: an opinionated widget toolkit for building Bevy tooling (#19730)
# Objective

This PR introduces Bevy Feathers, an opinionated widget toolkit and
theming system intended for use by the Bevy Editor, World Inspector, and
other tools.

The `bevy_feathers` crate is incomplete and hidden behind an
experimental feature flag. The API is going to change significantly
before release.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-28 19:52:13 +00:00
jf908
fa9e303e61
Doc for X11 CursorGrabMode support (#19811)
# Objective

- Clarify that `CursorGrabMode::Locked` isn't supported on X11

Source:
https://docs.rs/winit/latest/winit/window/enum.CursorGrabMode.html#variant.Locked

## Solution

- Add it to the platform-specific docs
2025-06-28 18:54:21 +00:00
IceSentry
37bbbf753d
Use SmallVec instead of HashMap in MaterialProperties (#19846)
# Objective

- MaterialProperties uses HashMap for some data that is generally going
to be really small. This is likely using more memory than necessary

## Solution

- Use a SmallVec instead
- I used the size a StandardMaterial would need for all the backing
arrays

## Testing

- Tested the 3d_scene to confirm it still works

## Notes

I'm not sure if it made a measurable difference since I'm not sure how
to measure this. It's a bit hard to create an artificial workflow where
this would be the main bottleneck. This is very in the realm of
microoptimization.
2025-06-28 18:43:56 +00:00
Jan Hohenheim
fb2bbb043c
Nudge users into migrating to new default glTF coordinate conversion (#19816)
# Objective

*Step towards https://github.com/bevyengine/bevy/issues/19686*

We now have all the infrastructure in place to migrate Bevy's default
behavior when loading glTF files to respect their coordinate system.
Let's start migrating! For motivation, see the issue linked above

## Solution

- Introduce a feature flag called `gltf_convert_coordinates_default`
- Currently,`GltfPlugin::convert_coordinates` defaults to `false`
- If `gltf_convert_coordinates_default` is enabled,
`GltfPlugin::convert_coordinates` will default to `true`
- If `gltf_convert_coordinates_default` is not enabled *and*
`GltfPlugin::convert_coordinates` is false, we assume the user is
implicitly using the old behavior. Print a warning *once* in that case,
but only when a glTF was actually loaded
- A user can opt into the new behavior either
- Globally, by enabling `gltf_convert_coordinates_default` in their
`Cargo.toml`
  - Globally, by enabling `GltfPlugin::convert_coordinates`
  - Per asset, by enabling `GltfLoaderSettings::convert_coordinates`
- A user can explicitly opt out of the new behavior and silence the
warning by
- Enabling `gltf_convert_coordinates_default` in their `Cargo.toml` and
disabling `GltfPlugin::convert_coordinates`
- This PR also moves the existing release note into a migration guide
 
Note that I'm very open to change any features, mechanisms, warning
texts, etc. as needed :)

## Future Work

- This PR leaves all examples fully functional by not enabling this flag
internally yet. A followup PR will enable it as a `dev-dependency` and
migrate all of our examples involving glTFs to the new behavior.
- After 0.17 (and the RC before) lands, we'll gather feedback to see if
anything breaks or the suggested migration is inconvenient in some way
- If all goes well, we'll kill this flag and change the default of
`GltfPlugin::convert_coordinates` to `true` in 0.18


## Testing

- Ran examples with and without the flag

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: AlephCubed <76791009+AlephCubed@users.noreply.github.com>
2025-06-28 18:35:41 +00:00
charlotte 🌸
e6ba9a6d18
Type erased materials (#19667)
# Objective

Closes #18075

In order to enable a number of patterns for dynamic materials in the
engine, it's necessary to decouple the renderer from the `Material`
trait.

This opens the possibility for:
- Materials that aren't coupled to `AsBindGroup`.
- 2d using the underlying 3d bindless infrastructure.
- Dynamic materials that can change their layout at runtime.
- Materials that aren't even backed by a Rust struct at all.

## Solution

In short, remove all trait bounds from render world material systems and
resources. This means moving a bunch of stuff onto `MaterialProperties`
and engaging in some hacks to make specialization work. Rather than
storing the bind group data in `MaterialBindGroupAllocator`, right now
we're storing it in a closure on `MaterialProperties`. TBD if this has
bad performance characteristics.

## Benchmarks

- `many_cubes`:
`cargo run --example many_cubes --release --features=bevy/trace_tracy --
--vary-material-data-per-instance`:
![Screenshot 2025-06-26
235426](https://github.com/user-attachments/assets/10a0ee29-9932-4f91-ab43-33518b117ac5)

- @DGriffin91's Caldera
`cargo run --release --features=bevy/trace_tracy -- --random-materials`

![image](https://github.com/user-attachments/assets/ef91ba6a-8e88-4922-a73f-acb0af5b0dbc)


- @DGriffin91's Caldera with 20 unique material types (i.e.
`MaterialPlugin<M>`) and random materials per mesh
`cargo run --release --features=bevy/trace_tracy -- --random-materials`
![Screenshot 2025-06-27
000425](https://github.com/user-attachments/assets/9561388b-881d-46cf-8c3d-b15b3e9aedc7)


### TODO

- We almost certainly lost some parallelization from removing the type
params that could be gained back from smarter iteration.
- Test all the things that could have broken.
- ~Fix meshlets~

## Showcase

See [the
example](https://github.com/bevyengine/bevy/pull/19667/files#diff-9d768cfe1c3aa81eff365d250d3cbe5a63e8df63e81dd85f64c3c3cd993f6d94)
for a custom material implemented without the use of the `Material`
trait and thus `AsBindGroup`.


![image](https://github.com/user-attachments/assets/e3fcca7c-e04e-4a4e-9d89-39d697a9e3b8)

---------

Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
Co-authored-by: IceSentry <c.giguere42@gmail.com>
2025-06-27 22:57:24 +00:00
Talin
73a313200d
CoreRadio should require Checkable, not Checked. (#19836)
This was a mistake in my original PR #19778: a holdover from when
Checked was not a marker component.
2025-06-27 18:23:59 +00:00
ickshonpe
45a379cf2d
Opt-out for UI clipping (#19826)
# Objective

Opt-out for UI clipping, for motivation see issue #19821

## Solution

New zst component `OverrideClip`. A UI node entity with this component
will ignore any inherited clipping rect, so it will never get clipped
regardless of the `Overflow` settings of its ancestors.

#### Why use a marker component and not add a new variant to `Overflow`
instead?
A separate marker component allows users to set both `Overflow` and
`OverrideClip` on the same node.

## Testing

Run the `overflow` example with the `OverrideClip` component added to
the `ImagNode`s and you will see that clipping is disabled.
2025-06-27 17:17:09 +00:00
charlotte 🌸
a0b90cd618
Resolution override (#19817)
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: atlv <email@atlasdostal.com>
2025-06-27 16:30:54 +00:00
atlv
410ca48023
cleanup constants (#19831)
# Objective

- i think const exprs werent supported in naga when these were written,
and we've just stuck with that since then. they're supported now so lets
use them

## Solution

- do that thang

## Testing

- transparency_3d, transmission, ssr, 3d_scene, couple others. they all
look fine
2025-06-27 07:02:03 +00:00
atlv
a256d3398a
use sequential bindings in bevy_sprite (#19830)
# Objective

- Use the terser api

## Solution

- Use the terser api

## Testing

- run sprite example it works
2025-06-27 06:59:02 +00:00
atlv
5fabb5343d
use wgpu TextureDataOrder (#19829)
# Objective

- Fixes #19140

## Solution

- Use TextureDataOrder

## Testing

- ran some examples that use ktx2 textures, they look fine
2025-06-27 06:57:29 +00:00
atlv
479c93d72b
updating: very very minorly (#19827)
# Objective

- fix thing missed during rust update

## Solution

- fix thing missed during rust update

## Testing

- cargo clippy
2025-06-26 21:48:20 +00:00
atlv
30800401b4
add native zstd support (#19793)
# Objective

- add support for alternate zstd backend through `zstd` for faster
decompression

## Solution

- make existing `zstd` feature only specify that support is required,
disambiguate which backend to use via two other features `zstd_native`
and `zstd_rust`.
- Similar to the approach taken by #18411, but we keep current behavior
by defaulting to the rust implementation because its safer, and isolate
this change.

NOTE: the default feature-set may seem to not currently require `zstd`,
but it does, it is enabled transitively by the `tonemapping_luts`
feature, which is a default feature. Thus this does not add default
features.

## Testing

- Cargo clippy on both feature combinations
2025-06-26 20:53:54 +00:00
atlv
b62b14c293
Add UVec to_extents helper method (#19807)
# Objective

- Simplify common usecase

## Solution

- Helper trait
2025-06-26 20:53:49 +00:00
charlotte 🌸
96dcbc5f8c
Ugrade to wgpu version 25.0 (#19563)
# Objective

Upgrade to `wgpu` version `25.0`.

Depends on https://github.com/bevyengine/naga_oil/pull/121

## Solution

### Problem

The biggest issue we face upgrading is the following requirement:
> To facilitate this change, there was an additional validation rule put
in place: if there is a binding array in a bind group, you may not use
dynamic offset buffers or uniform buffers in that bind group. This
requirement comes from vulkan rules on UpdateAfterBind descriptors.

This is a major difficulty for us, as there are a number of binding
arrays that are used in the view bind group. Note, this requirement does
not affect merely uniform buffors that use dynamic offset but the use of
*any* uniform in a bind group that also has a binding array.

### Attempted fixes

The easiest fix would be to change uniforms to be storage buffers
whenever binding arrays are in use:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<uniform> lights: types::Lights;
#else
@group(0) @binding(0) var<storage> view: array<View>;
@group(0) @binding(1) var<storage> lights: array<types::Lights>;
#endif
```

This requires passing the view index to the shader so that we know where
to index into the buffer:

```wgsl
struct PushConstants {
    view_index: u32,
}

var<push_constant> push_constants: PushConstants;
```

Using push constants is no problem because binding arrays are only
usable on native anyway.

However, this greatly complicates the ability to access `view` in
shaders. For example:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
mesh_view_bindings::view.view_from_world[0].z
#else
mesh_view_bindings::view[mesh_view_bindings::view_index].view_from_world[0].z
#endif
```

Using this approach would work but would have the effect of polluting
our shaders with ifdef spam basically *everywhere*.

Why not use a function? Unfortunately, the following is not valid wgsl
as it returns a binding directly from a function in the uniform path.

```wgsl
fn get_view() -> View {
#if BINDING_ARRAYS_ARE_USED
    let view_index = push_constants.view_index;
    let view = views[view_index];
#endif
    return view;
}
```

This also poses problems for things like lights where we want to return
a ptr to the light data. Returning ptrs from wgsl functions isn't
allowed even if both bindings were buffers.

The next attempt was to simply use indexed buffers everywhere, in both
the binding array and non binding array path. This would be viable if
push constants were available everywhere to pass the view index, but
unfortunately they are not available on webgpu. This means either
passing the view index in a storage buffer (not ideal for such a small
amount of state) or using push constants sometimes and uniform buffers
only on webgpu. However, this kind of conditional layout infects
absolutely everything.

Even if we were to accept just using storage buffer for the view index,
there's also the additional problem that some dynamic offsets aren't
actually per-view but per-use of a setting on a camera, which would
require passing that uniform data on *every* camera regardless of
whether that rendering feature is being used, which is also gross.

As such, although it's gross, the simplest solution just to bump binding
arrays into `@group(1)` and all other bindings up one bind group. This
should still bring us under the device limit of 4 for most users.

### Next steps / looking towards the future

I'd like to avoid needing split our view bind group into multiple parts.
In the future, if `wgpu` were to add `@builtin(draw_index)`, we could
build a list of draw state in gpu processing and avoid the need for any
kind of state change at all (see
https://github.com/gfx-rs/wgpu/issues/6823). This would also provide
significantly more flexibility to handle things like offsets into other
arrays that may not be per-view.

### Testing

Tested a number of examples, there are probably more that are still
broken.

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
2025-06-26 19:41:47 +00:00
charlotte 🌸
92e65d5eb1
Upgrade to Rust 1.88 (#19825) 2025-06-26 19:38:19 +00:00
Alix Bott
dd4479ed30
Fix PartialReflect::apply for maps, remove get_at/_mut from Map trait (#19802)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/14328
- `DynamicMap::drain` was broken (indices weren't cleared, causing a
panic when reading later)
- `PartialReflect::apply` was broken for maps and sets, because they
don't remove entries from the `self` map that aren't in the applied map.
- I discovered this bug when implementing MapEntities on a Component
containing a `HashMap<Entity, _>`. Because `apply` is used to reapply
the changes to the reflected map, the map ended up littered with a ton
of outdated entries.

## Solution

- Remove the separate `Vec` in `DynamicMap` and use the `HashTable`
directly, like it is in `DynamicSet`.
- Replace `MapIter` by `Box<dyn Iterator>` (like for `DynamicSet`), and
`Map::get_at` and `Map::get_at_mut` which are now unused.
- Now assume `DynamicMap` types are unordered and adjust documentation
accordingly.
- Fix documentation of `DynamicSet` (ordered -> unordered)
- Added `Map::retain` and `Set::retain`, and use them to remove excess
entries in `PartialReflect::apply` implementations.

## Testing

- Added `map::tests::apply` and `set::tests::apply` to validate
`<DynamicMap as PartialReflect>::apply` and `<DynamicSet as
PartialReflect>::apply`
2025-06-25 15:42:01 +00:00
François Mockers
97dcb279fb
CI tests can exit directly after taking a screenshot (#19806)
# Objective

- Currently, CI tests take a screenshot at frame X and exits at frame Y
with X < Y, and both number fixed
- This means tests can take longer than they actually need when taking
the screenshot is fast, and can fail to take the screenshot when it's
taking too long

## Solution

- Add a new event `ScreenshotAndExit` that exit directly after the
screenshot is saved
2025-06-24 22:44:30 +00:00
Conner Petzold
04c2b32be8
TilemapChunk cleanup (#19795)
# Objective

- Make follow-up changes from #18866 

## Solution

  - Switch from the on add observer to an on insert hook
  - Make the component immutable
  - Remove required components

## Testing

- `tilemap_chunk` example
2025-06-24 22:25:59 +00:00
Aevyrie
a3d406dd49
Upstream raycasting UVs (#19791)
# Objective

- Upstream mesh raycast UV support used in #19199

## Solution

- Compute UVs, debug a bunch of math issues with barycentric coordinates
and add docs.

## Testing

- Tested in diagetic UI in the linked PR.
2025-06-24 18:10:59 +00:00
dependabot[bot]
c7b5bc93c3
Update derive_more requirement from 1 to 2 (#19671)
Updates the requirements on
[derive_more](https://github.com/JelteF/derive_more) to permit the
latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/JelteF/derive_more/releases">derive_more's
releases</a>.</em></p>
<blockquote>
<h2>2.0.1</h2>
<p><a href="https://docs.rs/derive_more/2.0.1">API docs</a>
<a
href="https://github.com/JelteF/derive_more/blob/v2.0.1/CHANGELOG.md#201---2025-02-03">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/JelteF/derive_more/blob/master/CHANGELOG.md">derive_more's
changelog</a>.</em></p>
<blockquote>
<h2>2.0.1 - 2025-02-03</h2>
<h3>Added</h3>
<ul>
<li>Add crate metadata for the Rust Playground. This makes sure that the
Rust
Playground will have all <code>derive_more</code> features available
once
<a
href="https://docs.rs/selectors/latest/selectors"><code>selectors</code></a>
crate updates its
<code>derive_more</code> version.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/445">#445</a>)</li>
</ul>
<h2>2.0.0 - 2025-02-03</h2>
<h3>Breaking changes</h3>
<ul>
<li><code>use derive_more::SomeTrait</code> now imports macro only.
Importing macro with
its trait along is possible now via <code>use
derive_more::with_trait::SomeTrait</code>.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/406">#406</a>)</li>
<li>Top-level <code>#[display(&quot;...&quot;)]</code> attribute on an
enum now has defaulting behavior
instead of replacing when no wrapping is possible (no
<code>_variant</code> placeholder).
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/395">#395</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Associated types of type parameters not being treated as generics in
<code>Debug</code>
and <code>Display</code> expansions.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/399">#399</a>)</li>
<li><code>unreachable_code</code> warnings on generated code when
<code>!</code> (never type) is used.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/404">#404</a>)</li>
<li>Ambiguous associated item error when deriving <code>TryFrom</code>,
<code>TryInto</code> or <code>FromStr</code>
with an associated item called <code>Error</code> or <code>Err</code>
respectively.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/410">#410</a>)</li>
<li>Top-level <code>#[display(&quot;...&quot;)]</code> attribute on an
enum being incorrectly treated
as transparent or wrapping.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/395">#395</a>)</li>
<li>Omitted raw identifiers in <code>Debug</code> and
<code>Display</code> expansions.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/431">#431</a>)</li>
<li>Incorrect rendering of raw identifiers as field names in
<code>Debug</code> expansions.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/431">#431</a>)</li>
<li>Top-level <code>#[display(&quot;...&quot;)]</code> attribute on an
enum not working transparently
for directly specified fields.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/438">#438</a>)</li>
<li>Incorrect dereferencing of unsized fields in <code>Debug</code> and
<code>Display</code> expansions.
(<a
href="https://redirect.github.com/JelteF/derive_more/pull/440">#440</a>)</li>
</ul>
<h2>0.99.19 - 2025-02-03</h2>
<ul>
<li>Add crate metadata for the Rust Playground.</li>
</ul>
<h2>1.0.0 - 2024-08-07</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a78d8ee41d"><code>a78d8ee</code></a>
chore: Release</li>
<li><a
href="2aeee4d1c0"><code>2aeee4d</code></a>
Update changelog (<a
href="https://redirect.github.com/JelteF/derive_more/issues/446">#446</a>)</li>
<li><a
href="5afbaa1d8e"><code>5afbaa1</code></a>
Add Rust Playground metadata (<a
href="https://redirect.github.com/JelteF/derive_more/issues/445">#445</a>)</li>
<li><a
href="d6c3315f12"><code>d6c3315</code></a>
Prepare 2.0.0 release (<a
href="https://redirect.github.com/JelteF/derive_more/issues/444">#444</a>)</li>
<li><a
href="c5e5e82c0a"><code>c5e5e82</code></a>
Fix unsized fields usage in <code>Display</code>/<code>Debug</code>
derives (<a
href="https://redirect.github.com/JelteF/derive_more/issues/440">#440</a>,
<a
href="https://redirect.github.com/JelteF/derive_more/issues/432">#432</a>)</li>
<li><a
href="d391493a3c"><code>d391493</code></a>
Fix field transparency for top-level shared attribute in
<code>Display</code> (<a
href="https://redirect.github.com/JelteF/derive_more/issues/438">#438</a>)</li>
<li><a
href="f14c7a759a"><code>f14c7a7</code></a>
Fix raw identifiers usage in <code>Display</code>/<code>Debug</code>
derives (<a
href="https://redirect.github.com/JelteF/derive_more/issues/434">#434</a>,
<a
href="https://redirect.github.com/JelteF/derive_more/issues/431">#431</a>)</li>
<li><a
href="7b23de3d53"><code>7b23de3</code></a>
Update <code>convert_case</code> crate from 0.6 to 0.7 version (<a
href="https://redirect.github.com/JelteF/derive_more/issues/436">#436</a>)</li>
<li><a
href="cc9957e9cd"><code>cc9957e</code></a>
Fix <code>compile_fail</code> tests and make Clippy happy for 1.84 Rust
(<a
href="https://redirect.github.com/JelteF/derive_more/issues/435">#435</a>)</li>
<li><a
href="17d61c3118"><code>17d61c3</code></a>
Fix transparency and behavior of shared formatting on enums (<a
href="https://redirect.github.com/JelteF/derive_more/issues/395">#395</a>,
<a
href="https://redirect.github.com/JelteF/derive_more/issues/377">#377</a>,
<a
href="https://redirect.github.com/JelteF/derive_more/issues/411">#411</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/JelteF/derive_more/compare/v1.0.0...v2.0.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-24 11:13:04 +00:00
charlotte 🌸
7b5e4e3be0
Allow images to be resized on the GPU without losing data (#19462)
# Objective

#19410 added support for resizing images "in place" meaning that their
data was copied into the new texture allocation on the CPU. However,
there are some scenarios where an image may be created and populated
entirely on the GPU. Using this method would cause data to disappear, as
it wouldn't be copied into the new texture.

## Solution

When an image is resized in place, if it has no data in it's asset,
we'll opt into a new flag `copy_on_resize` which will issue a
`copy_texture_to_texture` command on the old allocation.

To support this, we require passing the old asset to all `RenderAsset`
implementations. This will be generally useful in the future for
reducing things like buffer re-allocations.

## Testing

Tested using the example in the issue.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-24 06:22:50 +00:00
atlv
8b6fe34570
remove unneeded dependency from bevy_render (#19794)
# Objective

- yeet cruft

## Solution

- yeet cruft

## Testing

- cargo clippy
2025-06-24 06:21:24 +00:00
Aevyrie
3cefe82aff
Projection Improvements (#18458)
# Objective

- Remove a component impl footgun
- Make projection code slightly nicer, and remove the need to import the
projection trait when using the methods on `Projection`.

## Solution

- Do the things.
2025-06-24 03:26:38 +00:00
atlv
82d62e606c
Split overloaded basis-universal feature into compressed_image_saver (#19789)
# Objective

- basis-universal feature is overloaded, you might not want the
compressed_image_saver but you may want basis-universal

## Solution

- split out compressed_image_saver

## Testing

- cargo clippy
2025-06-24 03:09:28 +00:00
Talin
9f551bb1e2
Core radio button and radio group (#19778)
# Objective

Core Radio Button and Radio Group widgets. Part of #19236
2025-06-24 00:38:31 +00:00
IceSentry
596eb48d8a
Add write_buffer_range to RawBufferVec and BufferVec (#19775)
# Objective

- Sometimes you only want to write parts of a buffer to the gpu instead
of reuploading the entire buffer. For example when doing data streaming.
- wgpu already supports this and you can do it manually from the user
side but it would be nice if it was built in.

## Solution

- Add `write_buffer_range()` to `RawBufferVec` and `BufferVec` that will
only upload the data contained in the specified range

## Testing

- I did not test it in bevy, but this implementation is copied from
something I used and tested at work
2025-06-24 00:33:41 +00:00
Jan Hohenheim
7aed3e411d
Implement serializable mesh (#19743)
# Objective

- Alternative to and closes #19545  
- Resolves #9790 by providing an alternative
- `Mesh` is meant as format optimized for the renderer. There are no
guarantees about how it looks, and breaking changes are expected
- This makes it not feasible to implement `Reflect` for all its fields
or `Serialize` it.
- However, (de)serializing a mesh has an important use case: send a mesh
over BRP to another process, like an editor!
- In my case, I'm making a navmesh editor and need to copy the level
that is running in the game into the editor process
  - Assets don't solve this because
    - They don't work over BRP #19709 and 
    - The meshes may be procedural
- So, we need a way to (de)serialize a mesh for short-term
transmissions.

## Solution

- Like `SerializedAnimationGraph` before, let's make a `SerializedMesh`!
- This type's fields are all `private` because we want to keep the
internals of `Mesh` hidden, and exposing them
  through this secondary struct would be counter-productive to that
- All this struct can do is be serialized, be deserialized, and be
converted to and from a mesh
- It's not a lossless transmission: the handle for morph targets is
ignored, and things like the render usages make no sense to be
transmitted imo

## Future Work

The same song and dance needs to happen for `Image`, but I can live with
completely white meshes for the moment lol

## Testing

- Added a simple test

---------

Co-authored-by: atlv <email@atlasdostal.com>
2025-06-24 00:32:34 +00:00
Jan Hohenheim
f3d94f3958
Allow setting correct glTF coordinate conversions globally (#19685)
# Objective

- Followup to https://github.com/bevyengine/bevy/pull/19633
- As discussed, it's a bit cumbersome to specify that you want the
correct orientation every single time
- Also, glTFs loaded from third parties will still be loaded incorrectly

## Solution

- Allow opting into the new behavior globally or per-asset
- Also improved some docs while on it :)

## Testing

- Ran the animation examples
- Ran the test scene from the last PR with all configuration
combinations
2025-06-24 00:23:34 +00:00
urben1680
546711b807
Split EntityClonerBuilder in OptOut and OptIn variants (#19649)
# Objective

Further tests after #19326 showed that configuring `EntityCloner` with
required components is bug prone and the current design has several
weaknesses in it's API:

- Mixing `EntityClonerBuilder::allow` and `EntityClonerBuilder::deny`
requires extra care how to support that which has an impact on
surrounding code that has to keep edge cases in mind. This is especially
true for attempts to fix the following issues. There is no use-case
known (to me) why someone would mix those.
- A builder with `EntityClonerBuilder::allow_all` configuration tries to
support required components like `EntityClonerBuilder::deny_all` does,
but the meaning of that is conflicting with how you'd expect things to
work:
- If all components should be cloned except component `A`, do you also
want to exclude required components of `A` too? Or are these also valid
without `A` at the target entity?
- If `EntityClonerBuilder::allow_all` should ignore required components
and not add them to be filtered away, which purpose has
`EntityClonerBuilder::without_required_components` for this cloner?
- Other bugs found with the linked PR are:
- Denying `A` also denies required components of `A` even when `A` does
not exist at the source entity
- Allowing `A` also allows required components of `A` even when `A` does
not exist at the source entity
- Adding `allow_if_new` filters to the cloner faces the same issues and
require a common solution to dealing with source-archetype sensitive
cloning

Alternative to #19632 and #19635.

# Solution

`EntityClonerBuilder` is made generic and split into
`EntityClonerBuilder<OptOut>` and `EntityClonerBuilder<OptIn>`

For an overview of the changes, see the migration guide. It is generally
a good idea to start a review of that.

## Algorithm

The generic of `EntityClonerBuilder` contains the filter data that is
needed to build and clone the entity components.

As the filter needs to be borrowed mutably for the duration of the
clone, the borrow checker forced me to separate the filter value and all
other fields in `EntityCloner`. The latter are now in the
`EntityClonerConfig` struct. This caused many changed LOC, sorry.

To make reviewing easier:

1. Check the migration guide
2. Many methods of `EntityCloner` now just call identitcal
`EntityClonerConfig` methods with a mutable borrow of the filter
3. Check `EntityClonerConfig::clone_entity_internal` which changed a bit
regarding the filter usage that is now trait powered (`CloneByFilter`)
to support `OptOut`, `OptIn` and `EntityClonerFilter` (an enum combining
the first two)
4. Check `OptOut` type that no longer tracks required components but has
a `insert_mode` field
5. Check `OptIn` type that has the most logic changes

# Testing

I added a bunch of tests that cover the new logic parts and the fixed
issues.

Benchmarks are in a comment a bit below which shows ~4% to 9%
regressions, but it varied wildly for me. For example at one run the
reflection-based clonings were on-par with main while the other are not,
and redoing that swapped the situation for both.

It would be really cool if I could get some hints how to get better
benchmark results or if you could run them on your machine too.

Just be aware this is not a Performance PR but a Bugfix PR, even if I
smuggled in some more functionalities. So doing changes to
`EntityClonerBuilder` is kind of required here which might make us bite
the bullet.

---------

Co-authored-by: eugineerd <70062110+eugineerd@users.noreply.github.com>
2025-06-24 00:12:08 +00:00
andriyDev
a7fdd6fc6f
Replace FULLSCREEN_SHADER_HANDLE with a FullscreenShader resource. (#19426)
# Objective

- Related to #19024.

## Solution

- Remove the `FULLSCREEN_SHADER_HANDLE` `weak_handle` with a resource
holding the shader handle.
- This also changes us from using `load_internal_asset` to
`embedded_asset`/`load_embedded_asset`.
- All uses have been migrated to clone the `FullscreenShader` resource
and use its `to_vertex_state` method.

## Testing

- `anti_aliasing` example still works.
- `bloom_3d` example still works.

---------

Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
2025-06-24 00:02:23 +00:00
jf908
9f376e2537
Update doc about Windows CursorGrabMode support (#19192)
# Objective

- Windows now supports `CursorGrabMode::Locked` in [Winit
0.30.10](https://github.com/rust-windowing/winit/releases/tag/v0.30.10)
which is automatically pulled in by cargo.

## Solution

- Remove the doc that says its unsupported.
2025-06-24 00:00:30 +00:00
Conner Petzold
3f187cf752
Add TilemapChunk rendering (#18866)
# Objective

An attempt to start building a base for first-party tilemaps (#13782).

The objective is to create a very simple tilemap chunk rendering plugin
that can be used as a building block for 3rd-party tilemap crates, and
eventually a first-party tilemap implementation.

## Solution

- Introduces two user-facing components, `TilemapChunk` and
`TilemapChunkIndices`, and a new material `TilemapChunkMaterial`.
- `TilemapChunk` holds the chunk and tile sizes, and the tileset image
- The tileset image is expected to be a layered image for use with
`texture_2d_array`, with the assumption that atlases or multiple images
would go through an asset loader/processor. Not sure if that should be
part of this PR or not..
- `TilemapChunkIndices` holds a 1d representation of all of the tile's
Option<u32> index into the tileset image.
- Indices are fixed to the size of tiles in a chunk (though maybe this
should just be an assertion instead?)
  - Indices are cloned and sent to the shader through a u32 texture.

## Testing

- Initial testing done with the `tilemap_chunk` example, though I need
to include some way to update indices as part of it.
- Tested wasm with webgl2 and webgpu
- I'm thinking it would probably be good to do some basic perf testing.

---

## Showcase

```rust
let chunk_size = UVec2::splat(64);
let tile_size = UVec2::splat(16);
let indices: Vec<Option<u32>> = (0..chunk_size.x * chunk_size.y)
    .map(|_| rng.gen_range(0..5))
    .map(|i| if i == 0 { None } else { Some(i - 1) })
    .collect();

commands.spawn((
    TilemapChunk {
        chunk_size,
        tile_size,
        tileset,
    },
    TilemapChunkIndices(indices),
));
```

![Screenshot 2025-04-17 at 11 54
56 PM](https://github.com/user-attachments/assets/850a53c1-16fc-405d-aad2-8ef5a0060fea)
2025-06-23 23:55:10 +00:00
Rob Parrett
d3ad66f033
Fix some typos (#19788)
# Objective

- Notice a word duplication typo
- Small quest to fix similar or nearby typos with my faithful companion
`\b(\w+)\s+\1\b`

## Solution

Fix em
2025-06-23 22:32:46 +00:00
Testare
da83232fa8
Let Component::map_entities defer to MapEntities (#19414)
# Objective

The objective of this PR is to enable Components to use their
`MapEntities` implementation for `Component::map_entities`.

With the improvements to the entity mapping system, there is definitely
a huge reduction in boilerplate. However, especially since
`(Entity)HashMap<..>` doesn't implement `MapEntities` (I presume because
the lack of specialization in rust makes `HashMap<Entity|X, Entity|X>`
complicated), when somebody has types that contain these hashmaps they
can't use this approach.

More so, we can't even depend on the previous implementation, since
`Component::map_entities` is used instead of
`MapEntities::map_entities`. Outside of implementing `Component `and
`Component::map_entities` on these types directly, the only path forward
is to create a custom type to wrap the hashmaps and implement map
entities on that, or split these components into a wrapper type that
implement `Component`, and an inner type that implements `MapEntities`.

## Current Solution
The solution was to allow adding `#[component(map_entities)]` on the
component. By default this will defer to the `MapEntities`
implementation.

```rust
#[derive(Component)]
#[component(map_entities)]
struct Inventory {
    items: HashMap<Entity, usize>
}

impl MapEntities for Inventory {
    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
        self.items = self.items
           .drain()
           .map(|(id, count)|(entity_mapper.get_mapped(id), count))
           .collect();
    }
}

```

You can use `#[component(map_entities = <function path>)]` instead to
substitute other code in for components. This function can also include
generics, but sso far I haven't been able to find a case where they are
needed.

```rust
#[derive(Component)]
#[component(map_entities = map_the_map)]
// Also works #[component(map_entities = map_the_map::<T,_>)]
struct Inventory<T> {
    items: HashMap<Entity, T>
}

fn map_the_map<T, M: EntityMapper>(inv: &mut Inventory<T>, entity_mapper: &mut M) {
    inv.items = inv.items
       .drain()
       .map(|(id, count)|(entity_mapper.get_mapped(id), count))
       .collect();
}

```

The idea is that with the previous changes to MapEntities, MapEntities
is implemented more for entity collections than for Components. If you
have a component that makes sense as both, `#[component(map_entities)]`
would work great, while otherwise a component can use
`#[component(map_entities = <function>)]` to change the behavior of
`Component::map_entities` without opening up the component type to be
included in other components.


## (Original Solution if you want to follow the PR)

The solution was to allow adding `#[component(entities)]` on the
component itself to defer to the `MapEntities` implementation

```rust
#[derive(Component)]
#[component(entities)]
struct Inventory {
    items: HashMap<Entity, usize>
}

impl MapEntities for Inventory {
    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
        self.items = self.items
           .drain()
           .map(|(id, count)|(entity_mapper.get_mapped(id), count))
           .collect();
    }
}

```

## Testing

I tested this by patching my local changes into my own bevy project. I
had a system that loads a scene file and executes some logic with a
Component that contains a `HashMap<Entity, UVec2>`, and it panics when
Entity is not found from another query. Since the 0.16 update this
system has reliably panicked upon attempting to the load the scene.

After patching my code in, I added `#[component(entities)]` to this
component, and I was able to successfully load the scene.

Additionally, I wrote a doc test.

## Call-outs
### Relationships
This overrules the default mapping of relationship fields. Anything else
seemed more problematic, as you'd have inconsistent behavior between
`MapEntities` and `Component`.
2025-06-23 21:05:04 +00:00
mgi388
efd17f133d
Rename num_entities to entity_count (#19781)
As discussed in
https://github.com/bevyengine/bevy/pull/19780#issuecomment-2994554024.
2025-06-23 05:08:02 +00:00
JMS55
0518eda2ad
bevy_solari: RIS for Direct Lighting (#19620)
# Objective

- Start the realtime direct lighting work for bevy solari

## Solution

- Setup all the CPU-side code for the realtime lighting path (minus some
parts for the temporal reuse I haven't written yet)
- Implement RIS with 32 samples to choose a good random light
- Don't sample a disk for the directional light, just treat it as a
single point. This is faster and not much worse quality.

## Future
- Spatiotemporal reuse (ReSTIR DI)
- Denoiser (DLSS-RR)
- Light tile optimization for faster light selection 
- Indirect lighting (ReSTIR GI)

## Testing
- Run the solari example to see realtime
- Run the solari example with `-- --pathtracer` to see the existing
pathtracer

---

## Showcase

1 frame direct lighting:

![image](https://github.com/user-attachments/assets/b70b968d-9c73-4983-9b6b-b60cace9b47a)

Accumulated pathtracer output:

![image](https://github.com/user-attachments/assets/d681bded-ef53-4dbe-bcca-96997c58c3be)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-23 00:47:10 +00:00
Alice Cecile
61a5a37584
Improve module structure of observers code (#19779)
# Objective

While working on #17607, I found myself confused and frustrated by the
tangled web woven by the various modules inside of our observers code.

Rather than tackle that as part of a big rewrite PR, I've decided to do
the mature (if frustrating) thing where you split out your trivial but
noisy refactoring first.

There are a large number of moving parts, especially in terms of
storage, and these are strewn willy-nilly across the module with no
apparent ordering. To make matters worse, this was almost all just
dumped into a multi-thousand LOC mod.rs at the root.

## Solution

I've reshuffled the modules, attempting to:
- reduce the size of the mod.rs file
- organize structs so that smaller structs are found after the larger
structs that contain them
- group related functionality together
- document why modules exist, and their broad organization

No functional changes have been made here, although I've had to increase
the visibility of a few fields from private to pub(crate) or pub(super)
to keep things compiling.

During these changes, I've opted for the lazy private module, public
re-export strategy, to avoid causing any breakages, both within and
outside of `bevy` itself. I think we can do better, but I want to leave
that for a proper cleanup pass at the end. There's no sense maintaining
migration guides and forcing multiple breaking changes throughout the
cycle.

## Testing

No functional changes; relying on existing test suite and the Rust
compiler.
2025-06-22 23:25:25 +00:00
theotherphil
7645ce91ed
Add newlines before impl blocks (#19746)
# Objective

Fix https://github.com/bevyengine/bevy/issues/19617 

# Solution

Add newlines before all impl blocks.

I suspect that at least some of these will be objectionable! If there's
a desired Bevy style for this then I'll update the PR. If not then we
can just close it - it's the work of a single find and replace.
2025-06-22 23:07:02 +00:00
github-actions[bot]
a466084167
Bump Version after Release (#19774)
Bump version after release
This PR has been auto-generated

Fixes #19766

---------

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
2025-06-22 23:06:43 +00:00
Trashtalk217
6dbe3600ed
Add num_entities() to World (#19780)
# Objective

There is a lot of `world.entities().len()`, especially in tests. In
tests, usually, the assumption is made that empty worlds do not contain
any entities. This is about to change (#19711), and as such all of these
tests are failing for that PR.

## Solution

`num_entities` is a convenience method that returns the number of
entities inside a world. It can later be adapted to exclude 'unexpected'
entities, associated with internal data structures such as Resources,
Queries, Systems. In general I argue for a separation of concepts where
`World` ignores internal entities in methods such as `iter_entities()`
and `clear_entities()`, that discussion is, however, separate from this
PR.

## Testing

I replaced most occurrences of `world.entities().len()` with
`world.num_entities()` and the tests passed.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-22 22:48:35 +00:00
urben1680
c6ae964709
EntityWorldMut methods do not automatically overwrite Relationship components (#19601)
# Objective

Some methods and commands carelessly overwrite `Relationship`
components. This may overwrite additional data stored at them which is
undesired.

Part of #19589

## Solution

A new private method will be used instead of insert:
`modify_or_insert_relation_with_relationship_hook_mode`.

This method behaves different to `insert` if `Relationship` is a larger
type than `Entity` and already contains this component. It will then use
the `modify_component` API and a new `Relationship::set_risky` method to
set the related entity, keeping all other data untouched.

For the `replace_related`(`_with_difference`) methods this also required
a `InsertHookMode` parameter for efficient modifications of multiple
children. The changes here are limited to the non-public methods.

I would appreciate feedback if this is all good.

# Testing

Added tests of all methods that previously could reset `Relationship`
data.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-22 00:22:05 +00:00
eugineerd
2d897380a0
add missing #[track_caller] (#19769)
# Objective

I've noticed that some methods with `MaybeLocation::caller` don't have
`#[track_caller]` which resulted in wrong locations reported when
`track_location` is enabled.

## Solution

add `#[track_caller]` to them.
2025-06-21 18:05:58 +00:00
Talin
4ff595a4bc
New simplified "click to focus" logic for core widgets. (#19736)
Click to focus is now a global observer.

# Objective

Previously, the "click to focus" behavior was implemented in each
individual headless widget, producing redundant logic.

## Solution

The new scheme is to have a global observer which looks for pointer down
events and triggers an `AcquireFocus` event on the target. This event
bubbles until it finds an entity with `TabIndex`, and then focuses it.

## Testing

Tested the changes using the various examples that have focusable
widgets. (This will become easier to test when I add focus ring support
to the examples, but that's for another day. For now you just have to
know which keys to press.)

## Migration

This change is backwards-compatible. People who want the new behavior
will need to install the new plugin.
2025-06-21 18:05:26 +00:00
ickshonpe
45a3f3d138
Color interpolation in OKLab, OKLCH spaces for UI gradients (#19330)
# Objective

Add support for interpolation in OKLab and OKLCH color spaces for UI
gradients.

## Solution
* New `InterpolationColorSpace` enum with `OkLab`, `OkLch`, `OkLchLong`,
`Srgb` and `LinearRgb` variants.
  * Added a color space specialization to the gradients pipeline.
* Added support for interpolation in OkLCH and OkLAB color spaces to the
gradients shader. OKLCH interpolation supports both short and long hue
paths. This is mostly based on the conversion functions from
`bevy_color` except that interpolation in polar space uses radians.
  * Added `color_space` fields to each gradient type.

## Testing

The `gradients` example has been updated to demonstrate the different
color interpolation methods.
Press space to cycle through the different options.

---

## Showcase


![color_spaces](https://github.com/user-attachments/assets/e10f8342-c3c8-487e-b386-7acdf38d638f)
2025-06-21 15:06:35 +00:00
Lailatova
5d5a95fa6e
Fix issue 19734: add dependency on bevy_utils for the bevy_ecs test. (#19738)
Without this dependency, the bevy_ecs tests fail with missing as_string
methods.

# Objective

 - Fixes #19734

## Solution

- add bevy_utils with feature = "Debug" to dev-dependencies 

## Testing

- Ran `cargo test -p bevy_ecs`
- Ran `taplo fmt --check`

---
2025-06-21 15:05:04 +00:00
MevLyshkin
84f21f7c8a
Schema types metadata (#19524)
# Objective

- Currently there is predefinied list of supported DataTypes that can be
detected on Bevy JSON Schema generation and mapped as reflect_types
array elements.
- Make it possible to register custom `reflectTypes` mappings for Bevy
JSON Schema.

## Solution

- Create a `SchemaTypesMetadata` Resource that will hold mappings for
`TypeId` of `TypeData`. List is bigger from beggining and it is possible
to expand it without forking package.

## Testing

- I use it for quite a while in my game, I have a fork of bevy_remote
with more changes that later I want to merge to main as well.

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2025-06-20 17:07:16 +00:00
Talin
9fdddf7089
Core Checkbox (#19665)
# Objective

This is part of the "core widgets" effort:
https://github.com/bevyengine/bevy/issues/19236.

## Solution

This adds the "core checkbox" widget type.

## Testing

Tested using examples core_widgets and core_widgets_observers.

Note to reviewers: I reorganized the code in the examples, so the diffs
are large because of code moves.
2025-06-20 16:37:18 +00:00
Giacomo Stevanato
35166d9029
Refactor bundle derive (#19749)
# Objective

- Splitted off from  #19491
- Make adding generated code to the `Bundle` derive macro easier
- Fix a bug when multiple fields are `#[bundle(ignore)]`

## Solution

- Instead of accumulating the code for each method in a different `Vec`,
accumulate only the names of non-ignored fields and their types, then
use `quote` to generate the code for each of them in the method body.
- To fix the bug, change the code populating the `BundleFieldKind` to
push only one of them per-field (previously each `#[bundle(ignore)]`
resulted in pushing twice, once for the correct
`BundleFieldKind::Ignore` and then again unconditionally for
`BundleFieldKind::Component`)

## Testing

- Added a regression test for the bug that was fixed
2025-06-20 16:36:08 +00:00
Emerson Coskey
8e1d0051d2
Fix QueryData derive codegen (#19750)
Custom derived `QueryData` impls currently generate `Item` structs with
the lifetimes swapped, which blows up the borrow checker sometimes.

See:
https://discord.com/channels/691052431525675048/749335865876021248/1385509416086011914

could add a regression test, TBH I don't know the error well enough to
do that minimally. Seems like it's that both lifetimes on
`QueryData::Item` need to be covariant, but I'm not sure.
2025-06-20 15:48:16 +00:00
theotherphil
b6bd205e8a
Gate Reflect derive behind feature flag (#19745)
# Objective

Fix https://github.com/bevyengine/bevy/issues/19733

## Solution

Gate reflect features behind `feature(bevy_reflect)`

## Tests

None
2025-06-19 21:58:17 +00:00
theotherphil
d2e1f725db
deny(missing_docs) for bevy_window (#19655)
# Objective

Write some more boilerplate-y docs, to get one crate closer to closing
https://github.com/bevyengine/bevy/issues/3492.
2025-06-19 19:33:49 +00:00
theotherphil
b129764924
deny(missing_docs) for bevy_asset_macros (#19719)
# Objective

More boilerplate docs, towards
https://github.com/bevyengine/bevy/issues/3492.

Another place where https://github.com/bevyengine/bevy/issues/19537
might be worth doing as a follow up - I've added a comment on that
issue.
2025-06-19 02:02:39 +00:00
Chris Russell
d0550f58ae
Remove 's lifetime from WorldQuery::Fetch (#19720)
# Objective

Unblock #18162.

#15396 added the `'s` lifetime to `QueryData::Item` to make it possible
for query items to borrow from the state. The state isn't passed
directly to `QueryData::fetch()`, so it also added the `'s` lifetime to
`WorldQuery::Fetch` so that we can pass the borrows through there.

Unfortunately, having `WorldQuery::Fetch` borrow from the state makes it
impossible to have owned state, because we store the state and the
`Fetch` in the same `struct` during iteration.

## Solution

Undo the change to add the `'s` lifetime to `WorldQuery::Fetch`.

Instead, add a `&'s Self::State` parameter to `QueryData::fetch()` and
`QueryFilter::filter_fetch()` so that borrows from the state can be
passed directly to query items.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Emerson Coskey <emerson@coskey.dev>
2025-06-19 00:58:21 +00:00
François Mockers
4e694aea53
ECS: put strings only used for debug behind a feature (#19558)
# Objective

- Many strings in bevy_ecs are created but only used for debug: system
name, component name, ...
- Those strings make a significant part of the final binary and are no
use in a released game

## Solution

- Use [`strings`](https://linux.die.net/man/1/strings) to find ...
strings in a binary
- Try to find where they come from
- Many are made from `type_name::<T>()` and only used in error / debug
messages
- Add a new structure `DebugName` that holds no value if `debug` feature
is disabled
- Replace `core::any::type_name::<T>()` by `DebugName::type_name::<T>()`

## Testing

Measurements were taken without the new feature being enabled by
default, to help with commands

### File Size

I tried building the `breakout` example with `cargo run --release
--example breakout`

|`debug` enabled|`debug` disabled|
|-|-|
|81621776 B|77735728B|
|77.84MB|74.13MB|

### Compilation time

`hyperfine --min-runs 15 --prepare "cargo clean && sleep 5"
'RUSTC_WRAPPER="" cargo build --release --example breakout'
'RUSTC_WRAPPER="" cargo build --release --example breakout --features
debug'`

```
breakout' 'RUSTC_WRAPPER="" cargo build --release --example breakout --features debug'
Benchmark 1: RUSTC_WRAPPER="" cargo build --release --example breakout
  Time (mean ± σ):     84.856 s ±  3.565 s    [User: 1093.817 s, System: 32.547 s]
  Range (min … max):   78.038 s … 89.214 s    15 runs

Benchmark 2: RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
  Time (mean ± σ):     92.303 s ±  2.466 s    [User: 1193.443 s, System: 33.803 s]
  Range (min … max):   90.619 s … 99.684 s    15 runs

Summary
  RUSTC_WRAPPER="" cargo build --release --example breakout ran
    1.09 ± 0.05 times faster than RUSTC_WRAPPER="" cargo build --release --example breakout --features debug
```
2025-06-18 20:15:25 +00:00
Kristoffer Søholm
2119838e27
Add support for ButtonInput<Key> (#19684)
# Objective

While `KeyCode` is very often the correct way to interact with keyboard
input there are a bunch of cases where it isn't, notably most of the
symbols (e.g. plus, minus, different parentheses). Currently the only
way to get these is to read from `EventReader<KeyboardInput>`, but then
you'd have to redo the `ButtonInput` logic for pressed/released to e.g.
make zoom functionality that depends on plus/minus keys.

This has led to confusion previously, like
https://github.com/bevyengine/bevy/issues/3278

## Solution

Add a `ButtonInput<Key>` resource.

## Testing

Modified the `keyboard_input` example to test it.

## Open questions

I'm not 100% sure this is the right way forward, since it duplicates the
key processing logic and might make people use the shorter
`ButtonInput<Key>` even when it's not appropriate.

Another option is to add a new struct with both `Key` and `KeyCode`, and
use `ButtonInput` with that instead. That would make it more
explanatory, but that is a lot of churn.

The third alternative is to not do this because it's too niche.

I'll add more documentation and take it out of draft if we want to move
forward with it.
2025-06-18 20:15:03 +00:00
atlv
a1d3c6197f
rename Transform::compute_matrix to to_matrix (#19646)
# Objective

- Parity with #19643

## Solution

- Rename

## Testing

- None

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-18 05:37:25 +00:00
Lucas Franca
6f08bb84d2
Exposes Observer's system's name (#19611)
# Objective

Fixes #18726
Alternative to and closes #18797

## Solution

Create a method `Observer::system_name` to expose the name of the
`Observer`'s system

## Showcase

```rust
// Returns `my_crate::my_observer`
let observer = Observer::new(my_observer);
println!(observer.system_name());

// Returns `my_crate::method::{{closure}}`
let observer = Observer::new(|_trigger: Trigger<...>|);
println!(observer.system_name());

// Returns `custom_name`
let observer = Observer::new(IntoSystem::into_system(my_observer).with_name("custom_name"));
println!(observer.system_name());
```

## TODO
- [ ] Achieve cart's approval

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-17 22:38:31 +00:00
Malek
f3e7a4b048
Added clone bounds to EntityEvents that were missing them. (#19708)
# Objective

Lack of clone on certain builtin events

## Solution

Added clone to those events

## Testing

## Showcase
2025-06-17 21:22:32 +00:00
theotherphil
66086a2616
Add TypeIdMapExt trait to make TypeIdMap operations more ergonomic (#19683)
# Objective
 
Fix https://github.com/bevyengine/bevy/issues/19642 by enabling e.g.

```
map.get_type::<MyType>();
```

in place of

```
map.get(&TypeId::of::<MyType>());
```

## Solution

Add an extension trait `TypeIdMapExt` with `insert_type`, `get_type`,
`get_type_mut` and `remove_type` counterparts for `insert`, `get`,
`get_mut` and `remove`.

## Testing

Doc test.
2025-06-17 21:06:27 +00:00
Alice Cecile
1079b83af9
Revert "bevy_log: refactor how log layers are wired together (#19248)" (#19705)
This reverts commit 8661e914a5, aka
#19248.

Fixes #19689.
2025-06-17 20:41:30 +00:00
Jan Hohenheim
a750cfe4a1
Split CursorOptions off of Window (#19668)
# Objective

- Fixes #19627 
- Tackles part of #19644 
- Supersedes #19629
- `Window` has become a very very very big component
- As such, our change detection does not *really* work on it, as e.g.
moving the mouse will cause a change for the entire window
- We circumvented this with a cache
- But, some things *shouldn't* be cached as they can be changed from
outside the user's control, notably the cursor grab mode on web
- So, we need to disable the cache for that
- But because change detection is broken, that would result in the
cursor grab mode being set every frame the mouse is moved
- That is usually *not* what a dev wants, as it forces the cursor to be
locked even when the end-user is trying to free the cursor on the
browser
  - the cache in this situation is invalid due to #8949

## Solution

- Split `Window` into multiple components, each with working change
detection
- Disable caching of the cursor grab mode
- This will only attempt to force the grab mode when the `CursorOptions`
were touched by the user, which is *much* rarer than simply moving the
mouse.
- If this PR is merged, I'll do the exact same for the other
constituents of `Window` as a follow-up

## Testing

- Ran all the changed examples
2025-06-17 20:20:13 +00:00
Alejandro Pascual
d1c6fbea57
Support fallible one-shot systems (#19678)
Closes #19677.

I don't think that the output type needs to be `Send`. I've done some
test at it seems to work fine without it, which in IMO makes sense, but
please correct me if that is not the case.
2025-06-17 19:48:37 +00:00
atlv
2915a3b903
rename GlobalTransform::compute_matrix to to_matrix (#19643)
# Objective

- compute_matrix doesn't compute anything, it just puts an Affine3A into
a Mat4. the name is inaccurate

## Solution

- rename it to conform with to_isometry (which, ironically, does compute
a decomposition which is rather expensive)

## Testing

- Its a rename. If it compiles, its good to go

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-17 18:37:26 +00:00
Erick Z
20781371e8
Register ReflectSerialize for &'static str (#19680)
# Objective

- When trying to serialize an structure that contains `&'static str`
using only Reflection, I get the following error:
```
"type `&str` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. 
For certain types, this may need to be registered manually using `register_type_data` (stack: ... -> `core::option::Option<&str>` -> `&str`)")
```
## Solution

- Register `ReflectSerialize` for `&str`

## Testing

- `cargo run -p ci`: OK
2025-06-16 22:09:15 +00:00
ickshonpe
c0fa10b0c3
slider widget track click position UiScale fix (#19676)
# Objective

The position for track clicks in `core_slider` is calculated incorrectly
when using `UiScale`.

## Solution

`trigger.event().pointer_location.position` uses logical window
coordinates, that is:

`position = physical_position / window_scale_factor`

while `ComputedNodeTarget::scale_factor` returns the window scale factor
multiplied by Ui Scale:

`target_scale_factor = window_scale_factor * ui_scale`

So to get the physical position need to divide by the `UiScale`:

```
position * target_scale_factor / ui_scale
= (physical_postion / window_scale_factor) * (window_scale_factor * ui_scale) / ui_scale
=  physical_position
```

I thought this was fixed during the slider PR review, but must have got
missed somewhere or lost in a merge.

## Testing

Can test using the `core_widgets` example` with
`.insert_resource(UiScale(2.))` added to the bevy app.
2025-06-16 22:07:54 +00:00
HippoGamus
209866cc27
Fix Keyboard observer not updating SliderValue (#19661)
# Objective

When the `CoreSlider`s `on_change` is set to None, Keyboard input, like
ArrowKeys, does not update the `SliderValue`.

## Solution

Handle the missing case, like it is done for Pointer.

## Testing

- Did you test these changes?
Yes: core_widgets & core_widgets_observers
in both examples one has to remove / comment out the setting of
`CoreSlider::on_change` to test the case of `on_change` being none.

- Are there any parts that need more testing?
No not that I am aware of.

- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Yes: core_widgets & core_widgets_observers
in both examples one has to remove / comment out the setting of
`CoreSlider::on_change` to test the case of `on_change` being none.

- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
I tested on linux + wayland. But it is unlikely that it would effect
outcomes.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-16 22:05:19 +00:00
atlv
7c2289c96e
Clarify GlobalTransform::to_isometry doc (#19645)
# Objective

- to_isometry is not a direct conversion, it involves computation. the
docs could be clearer

## Solution

- Improve docs

## Testing

- its docs
2025-06-16 22:02:30 +00:00
Alice Cecile
7237c2173b
Make observers metadata / storage publicly visible (#19608)
# Objective

Our strategy for storing observers is made up of several moving parts,
which are ultimately fairly simple nested HashMaps.

These types are currently `pub`, but lack any meaningful way to access
this data.

We have three options here: 

1. Make these internals not `pub` at all.
2. Make the data read-only accessible.
3. Make the data mutably accessible.

## Solution

I've opted for option 2, exposing read-only values. This is consistent
with our existing approach to the ECS internals, allowing for easier
debugging without risking wanton data corruption. If one day you would
like to mutably access this data, please open an issue clearly
explaining what you're trying to do.

This was a pretty mechanical change, exposing fields via getters. I've
also opted to do my best to clarify some field names and documentation:
please double-check those for correctness. It was hard to be fully
confident, as the field names and documentation was not very clear ;)

## Testing

I spent some time going through the code paths, making sure that users
can trace all the way from `World` to the leaf nodes. Reviewers, please
ensure the same!

## Notes for reviewers

This is part of a broader observer overhaul: I fully expect us to change
up these internals and break these shiny new APIs. Probably even within
the same cycle!

But clean up your work area first: this sort of read-only getter and
improved docs will be important to replace as we work.
2025-06-16 22:00:33 +00:00
ickshonpe
0c63aa2405
Document TextShadow not supported by Text2d (#19533)
# Objective

Document `TextShadow` not supported by `Text2d`

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-16 21:55:32 +00:00
Jan Hohenheim
9b743d2a43
Allow users to fix glTF coordinate system imports (#19633)
# Objective

*Fixes #5670 as an opt-in for now*

glTF uses the following coordinate system:

- forward: Z
- up: Y
- right: -X

and Bevy uses:

- forward: -Z
- up: Y
- right: X

For the longest time, Bevy has simply ignored this distinction. That
caused issues when working across programs, as most software respects
the
glTF coordinate system when importing and exporting glTFs. Your scene
might have looked correct in Blender, Maya, TrenchBroom, etc. but
everything would be flipped when importing it into Bevy!

## Solution

Add an option to the glTF loader to perform coordinate conversion. Note
that this makes a distinction in the camera nodes, as glTF uses a
different coordinate system for them.

## Follow Ups

- Add global glTF loader settings, similar to the image loader, so that
users can make third-party crates also load their glTFs with corrected
coordinates
- Decide on a migration strategy to make this the future default
  - Create an issue
- Get feedback from Patrick Walton and Cart (not pinging them here to
not spam them)
  - Include this pic for reference of how Blender assumes -Y as forward:

![image](https://github.com/user-attachments/assets/8f5ae364-48f0-46e4-922b-50bccb8d58b3)

## Testing

I ran all glTF animation examples with the new setting enabled to
validate that they look the same, just flipped.

Also got a nice test scene from Chris that includes a camera inside the
glTF. Thanks @ChristopherBiscardi!

Blender (-Y forward): 

![image](https://github.com/user-attachments/assets/129013f1-a025-488a-8764-c7ee5e7019a1)

Bevy (-Z forward, but the model looks the wrong way):

![image](https://github.com/user-attachments/assets/842e00e0-48ce-4ca7-a88e-ea458ecbf852)

Bevy with `convert_coordinates` enabled (-Z forward):

![image](https://github.com/user-attachments/assets/e97f3797-75a0-4d2b-ac54-130ba69f0a3c)

Validation that the axes are correct with F3D's glTF viewer (+Z
forward):

![image](https://github.com/user-attachments/assets/b9f02adf-a7b0-4a18-821f-fdd04426d3bd)
2025-06-16 21:47:34 +00:00
mgi388
1f2fd3d29d
Fix SubStates with multiple source states not reacting to all source changes (#19595)
# Objective

- Fix issue where `SubStates` depending on multiple source states would
only react when _all_ source states changed simultaneously.
- SubStates should be created/destroyed whenever _any_ of their source
states transitions, not only when all change together.

# Solution

- Changed the "did parent change" detection logic from AND to OR. We
need to check if _any_ of the event readers changed, not if _all_ of
them changed.
- See
https://github.com/bevyengine/bevy/actions/runs/15610159742/job/43968937544?pr=19595
for failing test proof before I pushed the fix.
- The generated code we want needs `||`s not `&&`s like this:

```rust
fn register_sub_state_systems_in_schedule<T: SubStates<SourceStates = Self>>(schedule: &mut Schedule) {
  let apply_state_transition = |(mut ereader0, mut ereader1, mut ereader2): (
      EventReader<StateTransitionEvent<S0::RawState>>,
      EventReader<StateTransitionEvent<S1::RawState>>,
      EventReader<StateTransitionEvent<S2::RawState>>,
  ),
      event: EventWriter<StateTransitionEvent<T>>,
      commands: Commands,
      current_state_res: Option<ResMut<State<T>>>,
      next_state_res: Option<ResMut<NextState<T>>>,
      (s0, s1, s2): (
          Option<Res<State<S0::RawState>>>,
          Option<Res<State<S1::RawState>>>,
          Option<Res<State<S2::RawState>>>,
  )| {
    // With `||` we can correctly count parent changed if any of the sources changed.
    let parent_changed = (ereader0.read().last().is_some()
        || ereader1.read().last().is_some()
        || ereader2.read().last().is_some());
    let next_state = take_next_state(next_state_res);
    if !parent_changed && next_state.is_none() {
        return;
    }
    // ...
  }
}
```

# Testing

- Add new test.
- Check the fix worked in my game.
2025-06-16 21:34:22 +00:00
SilentSpaceTraveller
8661e914a5
bevy_log: refactor how log layers are wired together (#19248)
# Objective

Current way to wire `Layer`s together using `layer.with(new_layer)` in
the `bevy_log` plugin is brittle and not flexible. As #17722
demonstrated, the current solution makes it very hard to do any kind of
advanced wiring, as the type system of `tracing::Subscriber` gets in the
way very quickly (the type of each new layer depends on the type of the
previous ones). We want to make it easier to have more complex wiring of
`Layers`. It would be hard to solve #19085 without it

## Solution
It aims to be functionally equivalent.
- Replace of using `layer.with(new_layer)` . We now add `layer.boxed()`
to a `Vec<BoxedLayer>`. It is a solution recommended by
`tracing_subscriber::Layer` for complex wiring cases (See
https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html#runtime-configuration-with-layers)
- Do some refactoring and clean up that is now enabled by the new
solution

## Testing
- Ran CI locally on Linux
- Ran the logs examples
- Need people familiar with the features `trace`, `tracing-chrome`,
`tracing-tracy` to check that it still works as expected
- Need people with access to `ios`, `android` and `wasm` to check it as
well.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2025-06-16 21:30:55 +00:00
theotherphil
3b25b38bdc
deny(missing_docs) for bevy_reflect (#19481)
## Objective

Deny missing docs in bevy_reflect, towards
https://github.com/bevyengine/bevy/issues/3492.

## Solution

Add the missing docs!

## Testing

N/A
2025-06-16 21:26:24 +00:00
Austreelis
6db71367d4
allow access to the source error of AssetLoaderError and downcasting (#19471)
# Objective

I have a custom asset loader, and need access to the error it reports
when failing to load (e.g. through `AssetLoadFailedEvent { error:
AssetLoadError::AssetLoaderError(loader_error), .. }`). However
`AssetLoaderError` doesn't expose its `<core::error::Error>::source()`
(i.e. its `error` field. It only formats it when `Display`ed.

*I haven't searched for issues about it.*

## Solution

- Annotate `AssetLoaderError`'s `error` field with `#[source]`.
- Don't include the error when `AssetLoaderError` is `Display`ed (when
one prints an error's source stack like a backtrace, it would now be
dupplicated).
- (optional, included as a separated commit) Add a getter for the `&dyn
Error` stored in the `error` field (whithin an `Arc`). This is more
ergonomic than using `Error::source()` because it casts an `&Arc<dyn
Error>` into an `&dyn Error`, meaning one has to downcast it twice to
get the original error from the loader, including once where you have to
specify the correct type of the *private* `error` field. So downcasting
from `Error::source()` effectively rely on the internal implementation
of `AssetLoaderError`. The getter instead return the trait object
directly, which mean it will directly downcast to the expected loader
error type.

I didn't included a test that checks that double-downcasting
`<AssetLoaderError as Error>::source()` doesn't break user code that
would rely on the private field's type.

## Testing

- Downcasting the trait objects for both `source()` and the `error()`
getter work as described above.
- `cargo test -p bevy_asset --all-features` pass without errors.

---------

Co-authored-by: austreelis <git@swhaele.net>
2025-06-16 21:24:01 +00:00
Chris Russell
f7e112a3c9
Let query items borrow from query state to avoid needing to clone (#15396)
# Objective

Improve the performance of `FilteredEntity(Ref|Mut)` and
`Entity(Ref|Mut)Except`.

`FilteredEntityRef` needs an `Access<ComponentId>` to determine what
components it can access. There is one stored in the query state, but
query items cannot borrow from the state, so it has to `clone()` the
access for each row. Cloning the access involves memory allocations and
can be expensive.


## Solution

Let query items borrow from their query state.  

Add an `'s` lifetime to `WorldQuery::Item` and `WorldQuery::Fetch`,
similar to the one in `SystemParam`, and provide `&'s Self::State` to
the fetch so that it can borrow from the state.

Unfortunately, there are a few cases where we currently return query
items from temporary query states: the sorted iteration methods create a
temporary state to query the sort keys, and the
`EntityRef::components<Q>()` methods create a temporary state for their
query.

To allow these to continue to work with most `QueryData`
implementations, introduce a new subtrait `ReleaseStateQueryData` that
converts a `QueryItem<'w, 's>` to `QueryItem<'w, 'static>`, and is
implemented for everything except `FilteredEntity(Ref|Mut)` and
`Entity(Ref|Mut)Except`.

`#[derive(QueryData)]` will generate `ReleaseStateQueryData`
implementations that apply when all of the subqueries implement
`ReleaseStateQueryData`.

This PR does not actually change the implementation of
`FilteredEntity(Ref|Mut)` or `Entity(Ref|Mut)Except`! That will be done
as a follow-up PR so that the changes are easier to review. I have
pushed the changes as chescock/bevy#5.

## Testing

I ran performance traces of many_foxes, both against main and against
chescock/bevy#5, both including #15282. These changes do appear to make
generalized animation a bit faster:

(Red is main, yellow is chescock/bevy#5)

![image](https://github.com/user-attachments/assets/de900117-0c6a-431d-ab62-c013834f97a9)


## Migration Guide

The `WorldQuery::Item` and `WorldQuery::Fetch` associated types and the
`QueryItem` and `ROQueryItem` type aliases now have an additional
lifetime parameter corresponding to the `'s` lifetime in `Query`. Manual
implementations of `WorldQuery` will need to update the method
signatures to include the new lifetimes. Other uses of the types will
need to be updated to include a lifetime parameter, although it can
usually be passed as `'_`. In particular, `ROQueryItem` is used when
implementing `RenderCommand`.

Before: 

```rust
fn render<'w>(
    item: &P,
    view: ROQueryItem<'w, Self::ViewQuery>,
    entity: Option<ROQueryItem<'w, Self::ItemQuery>>,
    param: SystemParamItem<'w, '_, Self::Param>,
    pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult;
```

After: 

```rust
fn render<'w>(
    item: &P,
    view: ROQueryItem<'w, '_, Self::ViewQuery>,
    entity: Option<ROQueryItem<'w, '_, Self::ItemQuery>>,
    param: SystemParamItem<'w, '_, Self::Param>,
    pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult;
```

---

Methods on `QueryState` that take `&mut self` may now result in
conflicting borrows if the query items capture the lifetime of the
mutable reference. This affects `get()`, `iter()`, and others. To fix
the errors, first call `QueryState::update_archetypes()`, and then
replace a call `state.foo(world, param)` with
`state.query_manual(world).foo_inner(param)`. Alternately, you may be
able to restructure the code to call `state.query(world)` once and then
make multiple calls using the `Query`.

Before:
```rust
let mut state: QueryState<_, _> = ...;
let d1 = state.get(world, e1);
let d2 = state.get(world, e2); // Error: cannot borrow `state` as mutable more than once at a time
println!("{d1:?}");
println!("{d2:?}");
```

After: 
```rust
let mut state: QueryState<_, _> = ...;

state.update_archetypes(world);
let d1 = state.get_manual(world, e1);
let d2 = state.get_manual(world, e2);
// OR
state.update_archetypes(world);
let d1 = state.query(world).get_inner(e1);
let d2 = state.query(world).get_inner(e2);
// OR
let query = state.query(world);
let d1 = query.get_inner(e1);
let d1 = query.get_inner(e2);

println!("{d1:?}");
println!("{d2:?}");
```
2025-06-16 21:05:41 +00:00
JMS55
e610badf6c
Add more PreviousViewData (#19605)
Add some more matrices to PreviousViewData for future use with
bevy_solari.
2025-06-16 04:54:26 +00:00
Alice Cecile
b7d2cb8547
Provide access to the original target of entity-events in observers (#19663)
# Objective

Getting access to the original target of an entity-event is really
helpful when working with bubbled / propagated events.

`bevy_picking` special-cases this, but users have requested this for all
sorts of bubbled events.

The existing naming convention was also very confusing. Fixes
https://github.com/bevyengine/bevy/issues/17112, but also see #18982.

## Solution

1. Rename `ObserverTrigger::target` -> `current_target`.
1. Store `original_target: Option<Entity>` in `ObserverTrigger`.
1. Wire it up so this field gets set correctly.
1. Remove the `target` field on the `Pointer` events from
`bevy_picking`.

Closes https://github.com/bevyengine/bevy/pull/18710, which attempted
the same thing. Thanks @emfax!

## Testing

I've modified an existing test to check that the entities returned
during event bubbling / propagation are correct.

## Notes to reviewers

It's a little weird / sad that you can no longer access this infromation
via the buffered events for `Pointer`. That said, you already couldn't
access any bubbled target. We should probably remove the `BufferedEvent`
form of `Pointer` to reduce confusion and overhead, but I didn't want to
do so here.

Observer events can be trivially converted into buffered events (write
an observer with an EventWriter), and I suspect that that is the better
migration if you want the controllable timing or performance
characteristics of buffered events for your specific use case.

## Future work

It would be nice to not store this data at all (and not expose any
methods) if propagation was disabled. That involves more trait
shuffling, and I don't think we should do it here for reviewability.

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2025-06-15 20:53:25 +00:00
Alice Cecile
3926f0208f
Make sequential_dispersed fn constant (#19659)
# Objective

- Try to make more of `bevy_color` const now that we have
const_float_arithmetic.

## Solution

Fail abjectly, because of our heavy use of traits.

I did find these functions though, so you can have a PR 🙃
2025-06-15 16:56:07 +00:00
Joel Singh
12ad7479a0
Add insert_child and remove_child methods (#19622)
# Objective

- `remove_child` was mentioned missing in #19556 and I realized that
`insert_child` was also missing.
- Removes the need to wrap a single entity with `&[]` with
`remove_children` and `insert_children`
- Would have also added `despawn_children` but #19283 does so. 

## Solution

- Simple wrapper around `remove_related`

## Testing

- Added `insert_child` and `remove_child` tests analgous to
`insert_children` and `remove_children` and then ran `cargo run -p ci --
test`
2025-06-15 16:52:25 +00:00
theotherphil
510efdf905
deny(missing_docs) for bevy_mikktspace (#19654)
# Objective

Remove allow(missing_docs) from bevy_mikktspace and add a simple
top-level doc comment, towards
https://github.com/bevyengine/bevy/issues/3492
2025-06-15 16:50:23 +00:00
Joona Aalto
38c3423693
Event Split: Event, EntityEvent, and BufferedEvent (#19647)
# Objective

Closes #19564.

The current `Event` trait looks like this:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The `Event` trait is used by both buffered events
(`EventReader`/`EventWriter`) and observer events. If they are observer
events, they can optionally be targeted at specific `Entity`s or
`ComponentId`s, and can even be propagated to other entities.

However, there has long been a desire to split the trait semantically
for a variety of reasons, see #14843, #14272, and #16031 for discussion.
Some reasons include:

- It's very uncommon to use a single event type as both a buffered event
and targeted observer event. They are used differently and tend to have
distinct semantics.
- A common footgun is using buffered events with observers or event
readers with observer events, as there is no type-level error that
prevents this kind of misuse.
- #19440 made `Trigger::target` return an `Option<Entity>`. This
*seriously* hurts ergonomics for the general case of entity observers,
as you need to `.unwrap()` each time. If we could statically determine
whether the event is expected to have an entity target, this would be
unnecessary.

There's really two main ways that we can categorize events: push vs.
pull (i.e. "observer event" vs. "buffered event") and global vs.
targeted:

|              | Push            | Pull                        |
| ------------ | --------------- | --------------------------- |
| **Global**   | Global observer | `EventReader`/`EventWriter` |
| **Targeted** | Entity observer | -                           |

There are many ways to approach this, each with their tradeoffs.
Ultimately, we kind of want to split events both ways:

- A type-level distinction between observer events and buffered events,
to prevent people from using the wrong kind of event in APIs
- A statically designated entity target for observer events to avoid
accidentally using untargeted events for targeted APIs

This PR achieves these goals by splitting event traits into `Event`,
`EntityEvent`, and `BufferedEvent`, with `Event` being the shared trait
implemented by all events.

## `Event`, `EntityEvent`, and `BufferedEvent`

`Event` is now a very simple trait shared by all events.

```rust
pub trait Event: Send + Sync + 'static {
    // Required for observer APIs
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

You can call `trigger` for *any* event, and use a global observer for
listening to the event.

```rust
#[derive(Event)]
struct Speak {
    message: String,
}

// ...

app.add_observer(|trigger: On<Speak>| {
    println!("{}", trigger.message);
});

// ...

commands.trigger(Speak {
    message: "Y'all like these reworked events?".to_string(),
});
```

To allow an event to be targeted at entities and even propagated
further, you can additionally implement the `EntityEvent` trait:

```rust
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This lets you call `trigger_targets`, and to use targeted observer APIs
like `EntityCommands::observe`:

```rust
#[derive(Event, EntityEvent)]
#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct Damage {
    amount: f32,
}

// ...

let enemy = commands.spawn((Enemy, Health(100.0))).id();

// Spawn some armor as a child of the enemy entity.
// When the armor takes damage, it will bubble the event up to the enemy.
let armor_piece = commands
    .spawn((ArmorPiece, Health(25.0), ChildOf(enemy)))
    .observe(|trigger: On<Damage>, mut query: Query<&mut Health>| {
        // Note: `On::target` only exists because this is an `EntityEvent`.
        let mut health = query.get(trigger.target()).unwrap();
        health.0 -= trigger.amount();
    });

commands.trigger_targets(Damage { amount: 10.0 }, armor_piece);
```

> [!NOTE]
> You *can* still also trigger an `EntityEvent` without targets using
`trigger`. We probably *could* make this an either-or thing, but I'm not
sure that's actually desirable.

To allow an event to be used with the buffered API, you can implement
`BufferedEvent`:

```rust
pub trait BufferedEvent: Event {}
```

The event can then be used with `EventReader`/`EventWriter`:

```rust
#[derive(Event, BufferedEvent)]
struct Message(String);

fn write_hello(mut writer: EventWriter<Message>) {
    writer.write(Message("I hope these examples are alright".to_string()));
}

fn read_messages(mut reader: EventReader<Message>) {
    // Process all buffered events of type `Message`.
    for Message(message) in reader.read() {
        println!("{message}");
    }
}
```

In summary:

- Need a basic event you can trigger and observe? Derive `Event`!
- Need the event to be targeted at an entity? Derive `EntityEvent`!
- Need the event to be buffered and support the
`EventReader`/`EventWriter` API? Derive `BufferedEvent`!

## Alternatives

I'll now cover some of the alternative approaches I have considered and
briefly explored. I made this section collapsible since it ended up
being quite long :P

<details>

<summary>Expand this to see alternatives</summary>

### 1. Unified `Event` Trait

One option is not to have *three* separate traits (`Event`,
`EntityEvent`, `BufferedEvent`), and to instead just use associated
constants on `Event` to determine whether an event supports targeting
and buffering or not:

```rust
pub trait Event: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    const BUFFERED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

Methods can then use bounds like `where E: Event<TARGETED = true>` or
`where E: Event<BUFFERED = true>` to limit APIs to specific kinds of
events.

This would keep everything under one `Event` trait, but I don't think
it's necessarily a good idea. It makes APIs harder to read, and docs
can't easily refer to specific types of events. You can also create
weird invariants: what if you specify `TARGETED = false`, but have
`Traversal` and/or `AUTO_PROPAGATE` enabled?

### 2. `Event` and `Trigger`

Another option is to only split the traits between buffered events and
observer events, since that is the main thing people have been asking
for, and they have the largest API difference.

If we did this, I think we would need to make the terms *clearly*
separate. We can't really use `Event` and `BufferedEvent` as the names,
since it would be strange that `BufferedEvent` doesn't implement
`Event`. Something like `ObserverEvent` and `BufferedEvent` could work,
but it'd be more verbose.

For this approach, I would instead keep `Event` for the current
`EventReader`/`EventWriter` API, and call the observer event a
`Trigger`, since the "trigger" terminology is already used in the
observer context within Bevy (both as a noun and a verb). This is also
what a long [bikeshed on
Discord](https://discord.com/channels/691052431525675048/749335865876021248/1298057661878898791)
seemed to land on at the end of last year.

```rust
// For `EventReader`/`EventWriter`
pub trait Event: Send + Sync + 'static {}

// For observers
pub trait Trigger: Send + Sync + 'static {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
    const TARGETED: bool = false;
    
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}
```

The problem is that "event" is just a really good term for something
that "happens". Observers are rapidly becoming the more prominent API,
so it'd be weird to give them the `Trigger` name and leave the good
`Event` name for the less common API.

So, even though a split like this seems neat on the surface, I think it
ultimately wouldn't really work. We want to keep the `Event` name for
observer events, and there is no good alternative for the buffered
variant. (`Message` was suggested, but saying stuff like "sends a
collision message" is weird.)

### 3. `GlobalEvent` + `TargetedEvent`

What if instead of focusing on the buffered vs. observed split, we
*only* make a distinction between global and targeted events?

```rust
// A shared event trait to allow global observers to work
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For buffered events and non-targeted observer events
pub trait GlobalEvent: Event {}

// For targeted observer events
pub trait TargetedEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is actually the first approach I implemented, and it has the neat
characteristic that you can only use non-targeted APIs like `trigger`
with a `GlobalEvent` and targeted APIs like `trigger_targets` with a
`TargetedEvent`. You have full control over whether the entity should or
should not have a target, as they are fully distinct at the type-level.

However, there's a few problems:

- There is no type-level indication of whether a `GlobalEvent` supports
buffered events or just non-targeted observer events
- An `Event` on its own does literally nothing, it's just a shared trait
required to make global observers accept both non-targeted and targeted
events
- If an event is both a `GlobalEvent` and `TargetedEvent`, global
observers again have ambiguity on whether an event has a target or not,
undermining some of the benefits
- The names are not ideal

### 4. `Event` and `EntityEvent`

We can fix some of the problems of Alternative 3 by accepting that
targeted events can also be used in non-targeted contexts, and simply
having the `Event` and `EntityEvent` traits:

```rust
// For buffered events and non-targeted observer events
pub trait Event: Send + Sync + 'static {
    fn register_component_id(world: &mut World) -> ComponentId { ... }
    fn component_id(world: &World) -> Option<ComponentId> { ... }
}

// For targeted observer events
pub trait EntityEvent: Event {
    type Traversal: Traversal<Self>;
    const AUTO_PROPAGATE: bool = false;
}
```

This is essentially identical to this PR, just without a dedicated
`BufferedEvent`. The remaining major "problem" is that there is still
zero type-level indication of whether an `Event` event *actually*
supports the buffered API. This leads us to the solution proposed in
this PR, using `Event`, `EntityEvent`, and `BufferedEvent`.

</details>

## Conclusion

The `Event` + `EntityEvent` + `BufferedEvent` split proposed in this PR
aims to solve all the common problems with Bevy's current event model
while keeping the "weirdness" factor minimal. It splits in terms of both
the push vs. pull *and* global vs. targeted aspects, while maintaining a
shared concept for an "event".

### Why I Like This

- The term "event" remains as a single concept for all the different
kinds of events in Bevy.
- Despite all event types being "events", they use fundamentally
different APIs. Instead of assuming that you can use an event type with
any pattern (when only one is typically supported), you explicitly opt
in to each one with dedicated traits.
- Using separate traits for each type of event helps with documentation
and clearer function signatures.
- I can safely make assumptions on expected usage.
- If I see that an event is an `EntityEvent`, I can assume that I can
use `observe` on it and get targeted events.
- If I see that an event is a `BufferedEvent`, I can assume that I can
use `EventReader` to read events.
- If I see both `EntityEvent` and `BufferedEvent`, I can assume that
both APIs are supported.

In summary: This allows for a unified concept for events, while limiting
the different ways to use them with opt-in traits. No more guess-work
involved when using APIs.

### Problems?

- Because `BufferedEvent` implements `Event` (for more consistent
semantics etc.), you can still use all buffered events for non-targeted
observers. I think this is fine/good. The important part is that if you
see that an event implements `BufferedEvent`, you know that the
`EventReader`/`EventWriter` API should be supported. Whether it *also*
supports other APIs is secondary.
- I currently only support `trigger_targets` for an `EntityEvent`.
However, you can technically target components too, without targeting
any entities. I consider that such a niche and advanced use case that
it's not a huge problem to only support it for `EntityEvent`s, but we
could also split `trigger_targets` into `trigger_entities` and
`trigger_components` if we wanted to (or implement components as
entities :P).
- You can still trigger an `EntityEvent` *without* targets. I consider
this correct, since `Event` implements the non-targeted behavior, and
it'd be weird if implementing another trait *removed* behavior. However,
it does mean that global observers for entity events can technically
return `Entity::PLACEHOLDER` again (since I got rid of the
`Option<Entity>` added in #19440 for ergonomics). I think that's enough
of an edge case that it's not a huge problem, but it is worth keeping in
mind.
- ~~Deriving both `EntityEvent` and `BufferedEvent` for the same type
currently duplicates the `Event` implementation, so you instead need to
manually implement one of them.~~ Changed to always requiring `Event` to
be derived.

## Related Work

There are plans to implement multi-event support for observers,
especially for UI contexts. [Cart's
example](https://github.com/bevyengine/bevy/issues/14649#issuecomment-2960402508)
API looked like this:

```rust
// Truncated for brevity
trigger: Trigger<(
    OnAdd<Pressed>,
    OnRemove<Pressed>,
    OnAdd<InteractionDisabled>,
    OnRemove<InteractionDisabled>,
    OnInsert<Hovered>,
)>,
```

I believe this shouldn't be in conflict with this PR. If anything, this
PR might *help* achieve the multi-event pattern for entity observers
with fewer footguns: by statically enforcing that all of these events
are `EntityEvent`s in the context of `EntityCommands::observe`, we can
avoid misuse or weird cases where *some* events inside the trigger are
targeted while others are not.
2025-06-15 16:46:34 +00:00
andriyDev
98c14e5917
Replace UntypedHandle from ReflectAsset with impl Into<UntypedAssetId>. (#19606)
# Objective

- A step towards #19024.
- Allow `ReflectAsset` to work with any `AssetId` not just `Handle`.
- `ReflectAsset::ids()` returns an iterator of `AssetId`s, but then
there's no way to use these ids, since all the other APIs in
`ReflectAsset` require a handle (and we don't have a reflect way to get
the handle).

## Solution

- Replace the `UntypedHandle` argument in `ReflectAsset` methods with
`impl Into<UntypedAssetId>`.
- This matches the regular asset API.
- This allows `ReflectAsset::ids()` to be more useful.

## Testing

- None.
2025-06-15 16:42:54 +00:00
urben1680
8bce3e46f2
Preserve extra data in RelationshipTarget with replace_related(_with_difference) (#19588)
# Objective

The methods and commands `replace_related` and
`replace_related_with_difference` may cause data stored at the
`RelationshipTarget` be lost when all original children are removed
before new children are added.

Part of https://github.com/bevyengine/bevy/issues/19589

## Solution

Fix the issue, either by removing the old children _after_ adding the
new ones and not _before_ (`replace_related_with_difference`) or by
taking the whole `RelationshipTarget` to modify it, not only the inner
collection (`replace_related`).

## Testing

I added a new test asserting the data is kept. I also added a general
test of these methods as they had none previously.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-06-15 16:41:28 +00:00
JMS55
6ecaf9de53
Add SkipDeferredLighting component (#19628)
Adds a new component for when you want to run the deferred gbuffer
prepass, but not the lighting pass.

This will be used by bevy_solari in the future, as it'll do it's own
shading pass, but still wants the gbuffer.
2025-06-15 16:30:08 +00:00