# Objective
It would be convenient to be able to quickly deny or allow all
components and resources on a `DynamicSceneBuilder` with a single method
call.
Context: #15210 renamed `{allow/deny}_all` to
`{allow/deny}_all_components`.
## Solution
Added two new methods to `DynamicSceneBuilder`, `allow_all` and
`deny_all`, which affect both the component and resource filters.
## Showcase
### Before
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all_components()
.deny_all_resources();
```
### After
```rust
let builder = DynamicSceneBuilder::from_world(world).deny_all();
```
The function `bevy_input::schedule::condition::Condition::or_else` has
been deprecated in favor of
`bevy_input::schedule::condition::Condition::or`. However the docs for
`ButtonInput` were still using the deprecated function in their example.
# Objective
The method names on `DynamicSceneBuilder` are misleading. Specifically,
`deny_all` and `allow_all` implies everything will be denied/allowed,
including all components and resources. In reality, these methods only
apply to components (which is mentioned in the docs).
## Solution
- change `deny_all` and `allow_all` to `deny_all_components` and
`allow_all_components`
- also, change the remaining methods to mention component where it makes
sense
We could also add the `deny_all` and `allow_all` methods back later,
only this time, they would deny/allow both resources and components.
## Showcase
### Before
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all()
.deny_all_resources()
.allow::<MyComponent>();
```
### After
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all_components()
.deny_all_resources()
.allow_component::<MyComponent>();
```
## Migration Guide
the following invocations on `DynamicSceneBuilder` should be changed by
users
- `with_filter` -> `with_component_filter`
- `allow` -> `allow_component`
- `deny` -> `deny_component`
- `allow_all` -> `allow_all_components`
- `deny_all` -> `deny_all_components`
# Objective
Fix#10284.
## Solution
When `DynamicSceneBuilder` extracts entities, they are cloned via
`PartialReflect::clone_value`, making them into dynamic versions of the
original components. This loses any custom `ReflectSerialize` type data.
Dynamic scenes are deserialized with the original types, not the dynamic
versions, and so any component with a custom serialize may fail. In this
case `Rect` and `Vec2`. The dynamic version includes the field names 'x'
and 'y' but the `Serialize` impl doesn't, hence the "expect float"
error.
The solution here: Instead of using `clone_value` to clone the
components, `FromReflect` clones and retains the original information
needed to serialize with any custom `Serialize` impls. I think using
something like `reflect_clone` from
(https://github.com/bevyengine/bevy/pull/13432) might make this more
efficient.
I also did the same when deserializing dynamic scenes to appease some of
the round-trip tests which use `ReflectPartialEq`, which requires the
types be the same and not a unique/proxy pair. I'm not sure it's
otherwise necessary. Maybe this would also be more efficient when
spawning dynamic scenes with `reflect_clone` instead of `FromReflect`
again?
An alternative solution would be to fall back to the dynamic version
when deserializing `DynamicScene`s if the custom version fails. I think
that's possible. Or maybe simply always deserializing via the dynamic
route for dynamic scenes?
## Testing
This example is similar to the original test case in #10284:
``` rust
#![allow(missing_docs)]
use bevy::{prelude::*, scene::SceneInstanceReady};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, (save, load).chain())
.observe(check)
.run();
}
static SAVEGAME_SAVE_PATH: &str = "savegame.scn.ron";
fn save(world: &mut World) {
let entity = world.spawn(OrthographicProjection::default()).id();
let scene = DynamicSceneBuilder::from_world(world)
.extract_entity(entity)
.build();
if let Some(registry) = world.get_resource::<AppTypeRegistry>() {
let registry = registry.read();
let serialized_scene = scene.serialize(®istry).unwrap();
// println!("{}", serialized_scene);
std::fs::write(format!("assets/{SAVEGAME_SAVE_PATH}"), serialized_scene).unwrap();
}
world.entity_mut(entity).despawn_recursive();
}
fn load(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(DynamicSceneBundle {
scene: asset_server.load(SAVEGAME_SAVE_PATH),
..default()
});
}
fn check(_trigger: Trigger<SceneInstanceReady>, query: Query<&OrthographicProjection>) {
dbg!(query.single());
}
```
## Migration Guide
The `DynamicScene` format is changed to use custom serialize impls so
old scene files will need updating:
Old:
```ron
(
resources: {},
entities: {
4294967299: (
components: {
"bevy_render:📷:projection::OrthographicProjection": (
near: 0.0,
far: 1000.0,
viewport_origin: (
x: 0.5,
y: 0.5,
),
scaling_mode: WindowSize(1.0),
scale: 1.0,
area: (
min: (
x: -1.0,
y: -1.0,
),
max: (
x: 1.0,
y: 1.0,
),
),
),
},
),
},
)
```
New:
```ron
(
resources: {},
entities: {
4294967299: (
components: {
"bevy_render:📷:projection::OrthographicProjection": (
near: 0.0,
far: 1000.0,
viewport_origin: (0.5, 0.5),
scaling_mode: WindowSize(1.0),
scale: 1.0,
area: (
min: (-1.0, -1.0),
max: (1.0, 1.0),
),
),
},
),
},
)
```
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- Fixes#14552
- Make the current note of `before` and `after` understandable.
- > The given set is not implicitly added to the schedule when this
system set is added.
## Solution
- Replace note in docs of [`after` and
`before`](https://docs.rs/bevy/latest/bevy/ecs/prelude/trait.IntoSystemConfigs.html#method.before)
- Note of after was removed completely, and links to `before`, because
they notes would be identical.
- Also encourage to use `.chain`, which is much simpler and safer to use
## Testing
- Checked the docs after running `cargo doc` and `cargo run -p ci --
lints`
- Are there any parts that need more testing?
- no need to test, but please review the text. If it is still including
the intended message and especially if its understandable.
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
`Capsule2d::sample_interior` uses the radius of the capsule for the
width of its rectangular section. It should be using two times the
radius for the full width!
I noticed this as I was getting incorrect results for angular inertia
approximated from a point cloud of points sampled on the capsule. This
hinted that something was wrong with the sampling.
## Solution
Multiply the radius by two to get the full width of the rectangular
section. With this, the sampling produces the correct result in my
tests.
# Objective
- implements ParsedPath::try_from<&str>
- resolves#14438
## Testing
- Added unit test for ParsedPath::try_from<&str>
Note: I don't claim to be an expert on lifetimes! That said I think it
makes sense that the error shares a lifetime with input string as deeper
down it is used to construct it.
# Objective
Thanks to #7207, we now have a way to validate at the type-level that a
reflected value is actually the type it says it is and not just a
dynamic representation of that type.
`dyn PartialReflect` values _might_ be a dynamic type, but `dyn Reflect`
values are guaranteed to _not_ be a dynamic type.
Therefore, we can start to add methods to `Reflect` that weren't really
possible before. For example, we should now be able to always get a
`&'static TypeInfo`, and not just an `Option<&'static TypeInfo>`.
## Solution
Add the `DynamicTyped` trait.
This trait is similar to `DynamicTypePath` in that it provides a way to
use the non-object-safe `Typed` trait in an object-safe way.
And since all types that derive `Reflect` will also derive `Typed`, we
can safely add `DynamicTyped` as a supertrait of `Reflect`. This allows
us to use it when just given a `dyn Reflect` trait object.
## Testing
You can test locally by running:
```
cargo test --package bevy_reflect
```
---
## Showcase
`Reflect` now has a supertrait of `DynamicTyped`, allowing `TypeInfo` to
be retrieved from a `dyn Reflect` trait object without having to unwrap
anything!
```rust
let value: Box<dyn Reflect> = Box::new(String::from("Hello!"));
// BEFORE
let info: &'static TypeInfo = value.get_represented_type_info().unwrap();
// AFTER
let info: &'static TypeInfo = value.reflect_type_info();
```
## Migration Guide
`Reflect` now has a supertrait of `DynamicTyped`. If you were manually
implementing `Reflect` and did not implement `Typed`, you will now need
to do so.
# Objective
Fixes#14980
## Solution
Only iterate over archetypes containing the component.
## Alternatives
Additionally, for each archetype, cache how many observers are watching
one of its components & use this to speed up the check for each affected
archetype ([implemented
here](55c89aa033)).
Benchmarking showed this to lead only to a minor speedup.
## Testing
There's both already a test checking that observers don't run after
being despawned as well as a regression test for the bug that
necessitates the check this PR optimizes.
# Objective
Fixes https://github.com/bevyengine/bevy/issues/13225
## Solution
Invalidate `TrackedRenderPass` internal state upon accessing internal
`wgpu::RenderPass`.
## Testing
- Tested by calling `set_bind_group` on `RenderPass` returned by
`TrackedRenderPass::wgpu_pass` and checking if in later `set_bind_group`
calls on `TrackedRenderPass` correct bind group is restored.
# Objective
- Finish resolving https://github.com/bevyengine/bevy/issues/15125
- Inserting bundles was implemented in
https://github.com/bevyengine/bevy/pull/15128 but removing bundles still
needed to be implemented.
## Solution
- Modified `bevy_ecs::reflect::entity_commands::remove_reflect` to
handle both components and bundles
- Modified documentation of `ReflectCommandExt` methods to reflect that
one can now use bundles with these commands.
## Testing
- Three tests were added to match the ones for inserting components.
# Objective
- Remove any ambiguity around how multiple `Observer` components work on
a single `Entity` by completely removing the concept.
- Fixes#15122
## Solution
- Removed type parameters from `Observer`, relying on a function pointer
to provide type information into the relevant aspects of running an
observer.
## Testing
- Ran CI locally.
- Checked `observers.rs` example continued to function as expected.
## Notes
This communicates to users of observers that only a single `Observer`
can be inserted onto an entity at a time within the established type
system. This has been achieved by erasing the type information from the
stored `ObserverSystem` and retrieving it again using a function
pointer. This has the downside of increasing the size of the `Observer`
component and increases the complexity of the observer runner. However,
this complexity was already present, and is in my opinion a worthwhile
tradeoff for the clearer user experience.
The other notable benefit is users no longer need to use the
`ObserverState` component to filter for `Observer` entities, and can
instead use `Observer` directly.
Technically this is a breaking change, since the type signature for
`Observer` has changed. However, it was so cumbersome to use that I
don't believe there are any instances in the wild of users directly
naming `Observer` types, instead relying on `ObserverState`, and the
methods provided by `App` and `World`. As can be seen in the diff, this
change had very little knock-on effects across Bevy.
## Migration Guide
If you filtered for observers using `Observer<A, B>`, instead filter for
an `Observer`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The module docs for `bevy_reflect::func` don't mention the
`FunctionRegistry`.
## Solution
Add a section about the `FunctionRegistry` to the module-level
documentation.
## Testing
You can test locally by running:
```
cargo test --doc --package bevy_reflect --all-features
```
# Objective
- Fixes https://github.com/bevyengine/bevy/pull/14991. The `cosmic-text`
shape run cache requires manual cleanup for old text that no longer
needs to be cached.
## Solution
- Add a system to trim the cache.
- Add an `average fps` indicator to the `text_debug` example.
## Testing
Tested with `cargo run --example text_debug`.
- **No shape run cache**: 82fps with ~1fps variance.
- **Shape run cache no trim**: 90-100fps with ~2-4fps variance
- **Shape run cache trim age = 1**: 90-100fps with ~2-8fps variance
- **Shape run cache trim age = 2**: 90-100fps with ~2-4fps variance
- **Shape run cache trim age = 2000**: 80-120fps with ~2-6fps variance
The shape run cache seems to increase average FPS but also increases
frame time variance (when there is dynamic text).
# Objective
The names of numerous rendering components in Bevy are inconsistent and
a bit confusing. Relevant names include:
- `AutoExposureSettings`
- `AutoExposureSettingsUniform`
- `BloomSettings`
- `BloomUniform` (no `Settings`)
- `BloomPrefilterSettings`
- `ChromaticAberration` (no `Settings`)
- `ContrastAdaptiveSharpeningSettings`
- `DepthOfFieldSettings`
- `DepthOfFieldUniform` (no `Settings`)
- `FogSettings`
- `SmaaSettings`, `Fxaa`, `TemporalAntiAliasSettings` (really
inconsistent??)
- `ScreenSpaceAmbientOcclusionSettings`
- `ScreenSpaceReflectionsSettings`
- `VolumetricFogSettings`
Firstly, there's a lot of inconsistency between `Foo`/`FooSettings` and
`FooUniform`/`FooSettingsUniform` and whether names are abbreviated or
not.
Secondly, the `Settings` post-fix seems unnecessary and a bit confusing
semantically, since it makes it seem like the component is mostly just
auxiliary configuration instead of the core *thing* that actually
enables the feature. This will be an even bigger problem once bundles
like `TemporalAntiAliasBundle` are deprecated in favor of required
components, as users will expect a component named `TemporalAntiAlias`
(or similar), not `TemporalAntiAliasSettings`.
## Solution
Drop the `Settings` post-fix from the component names, and change some
names to be more consistent.
- `AutoExposure`
- `AutoExposureUniform`
- `Bloom`
- `BloomUniform`
- `BloomPrefilter`
- `ChromaticAberration`
- `ContrastAdaptiveSharpening`
- `DepthOfField`
- `DepthOfFieldUniform`
- `DistanceFog`
- `Smaa`, `Fxaa`, `TemporalAntiAliasing` (note: we might want to change
to `Taa`, see "Discussion")
- `ScreenSpaceAmbientOcclusion`
- `ScreenSpaceReflections`
- `VolumetricFog`
I kept the old names as deprecated type aliases to make migration a bit
less painful for users. We should remove them after the next release.
(And let me know if I should just... not add them at all)
I also added some very basic docs for a few types where they were
missing, like on `Fxaa` and `DepthOfField`.
## Discussion
- `TemporalAntiAliasing` is still inconsistent with `Smaa` and `Fxaa`.
Consensus [on
Discord](https://discord.com/channels/691052431525675048/743663924229963868/1280601167209955431)
seemed to be that renaming to `Taa` would probably be fine, but I think
it's a bit more controversial, and it would've required renaming a lot
of related types like `TemporalAntiAliasNode`,
`TemporalAntiAliasBundle`, and `TemporalAntiAliasPlugin`, so I think
it's better to leave to a follow-up.
- I think `Fog` should probably have a more specific name like
`DistanceFog` considering it seems to be distinct from `VolumetricFog`.
~~This should probably be done in a follow-up though, so I just removed
the `Settings` post-fix for now.~~ (done)
---
## Migration Guide
Many rendering components have been renamed for improved consistency and
clarity.
- `AutoExposureSettings` → `AutoExposure`
- `BloomSettings` → `Bloom`
- `BloomPrefilterSettings` → `BloomPrefilter`
- `ContrastAdaptiveSharpeningSettings` → `ContrastAdaptiveSharpening`
- `DepthOfFieldSettings` → `DepthOfField`
- `FogSettings` → `DistanceFog`
- `SmaaSettings` → `Smaa`
- `TemporalAntiAliasSettings` → `TemporalAntiAliasing`
- `ScreenSpaceAmbientOcclusionSettings` → `ScreenSpaceAmbientOcclusion`
- `ScreenSpaceReflectionsSettings` → `ScreenSpaceReflections`
- `VolumetricFogSettings` → `VolumetricFog`
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Fixes#12639.
- `ReceivedCharacter` was deprecated in #12868 for 0.14, and should be
removed for 0.15.
## Solution
- Remove all instances of `ReceivedCharacter`, including the relevant
`#[allow(deprecated)]` lint attributes.
## Migration Guide
`ReceivedCharacter` was deprecated in 0.14 due to `winit` reworking
their keyboard system. It has now been fully removed. Switch to using
`KeyboardInput` instead.
```rust
// 0.14
fn listen_characters(events: EventReader<ReceivedCharacter>) {
for event in events.read() {
info!("{}", event.char);
}
}
// 0.15
fn listen_characters(events: EventReader<KeyboardInput>) {
for event in events.read() {
// Only check for characters when the key is pressed.
if !event.state.is_pressed() {
continue;
}
// Note that some keys such as `Space` and `Tab` won't be detected as a character.
// Instead, check for them as separate enum variants.
match &event.logical_key {
Key::Character(character) => {
info!("{} pressed.", character);
},
Key::Space => {
info!("Space pressed.");
},
_ => {},
}
}
}
```
# Objective
Fixes #15115
## Solution
Retrieve the size of the node's parent in a separate query and base
percentage border values on the parent node's width (or the width of the
viewport in the case of root nodes).
# Objective
Hello! I am adopting #11022 to resolve conflicts with `main`. tldr: this
removes `scale` in favour of `scaling_mode`. Please see the original PR
for explanation/discussion.
Also relates to #2580.
## Migration Guide
Replace all uses of `scale` with `scaling_mode`, keeping in mind that
`scale` is (was) a multiplier. For example, replace
```rust
scale: 2.0,
scaling_mode: ScalingMode::FixedHorizontal(4.0),
```
with
```rust
scaling_mode: ScalingMode::FixedHorizontal(8.0),
```
---------
Co-authored-by: Stepan Koltsov <stepan.koltsov@gmail.com>
# Objective
Reflection serialization can be difficult to debug. A lot of times a
type fails to be serialized and the user is left wondering where that
type came from.
This is most often encountered with Bevy's scenes. Attempting to
serialize all resources in the world will fail because some resources
can't be serialized.
For example, users will often get complaints about `bevy_utils::Instant`
not registering `ReflectSerialize`. Well, `Instant` can't be serialized,
so the only other option is to exclude the resource that contains it.
But what resource contains it? This is where reflection serialization
can get a little tricky (it's `Time<Real>` btw).
## Solution
Add the `debug_stack` feature to `bevy_reflect`. When enabled, the
reflection serializers and deserializers will keep track of the current
type stack. And this stack will be used in error messages to help with
debugging.
Now, if we unknowingly try to serialize `Time<Real>`, we'll get the
following error:
```
type `bevy_utils::Instant` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `bevy_time::time::Time<bevy_time::real::Real>` -> `bevy_time::real::Real` -> `bevy_utils::Instant`)
```
### Implementation
This makes use of `thread_local!` to manage an internal `TypeInfoStack`
which holds a stack of `&'static TypeInfo`. We push to the stack before
a type is (de)serialized and pop from the stack afterwards.
Using a thread-local should be fine since we know two (de)serializers
can't be running at the same time (and if they're running on separate
threads, then we're still good).
The only potential issue would be if a user went through one of the
sub-serializers, like `StructSerializer`. However, I don't think many
users are going through these types (I don't even know if we necessarily
want to keep those public either, but we'll save that for a different
PR). Additionally, this is just a debug feature that only affects error
messages, so it wouldn't have any drastically negative effect. It would
just result in the stack not being cleared properly if there were any
errors.
Lastly, this is not the most performant implementation since we now
fetch the `TypeInfo` an extra time. But I figured that for a debug tool,
it wouldn't matter too much.
### Feature
This also adds a `debug` feature, which enables the `debug_stack`
feature.
I added it because I think we may want to potentially add more debug
tools in the future, and this gives us a good framework for adding
those. Users who want all debug features, present and future, can just
set `debug`. If they only want this feature, then they can just use
`debug_stack`.
I also made the `debug` feature default to help capture the widest
audience (i.e. the users who want this feature but don't know they do).
However, if we think it's better as a non-default feature, I can change
it!
And if there's any bikeshedding around the name `debug_stack`, let me
know!
## Testing
Run the following command:
```
cargo test --package bevy_reflect --features debug_stack
```
---
## Changelog
- Added the `debug` and `debug_stack` features to `bevy_reflect`
- Updated the error messages returned by the reflection serializers and
deserializers to include more contextual information when the
`debug_stack` or `debug` feature is enabled
# Objective
`NoFrustumCulling` prevents meshes from being considered out of view
based on AABBs (sometimes useful for skinned meshes which don't
recalculate AABBs currently). it currently only applies for primary view
rendering, not for shadow rendering which can result in missing shadows.
## Solution
Add checks for `NoFrustumCulling` to `check_dir_light_mesh_visibility`
and `check_point_light_mesh_visibility` so that `NoFrustumCulling`
entities are rendered to all shadow views as well as all primary views.
# Objective
I noticed some issues in `screenshot` example:
1. Cursor icon won't return from `SystemCursorIcon::Progress` to default
icon, even though screen shot saving is done.
2. Panics when exiting window: ``called `Result::unwrap()` on an `Err`
value:
NoEntities("bevy_ecs::query::state::QueryState<bevy_ecs::entity::Entity,
bevy_ecs::query::filter::With<bevy_window:🪟:Window>>")``
## Solution
1. Caused by cursor updating system not responding to [`CursorIcon`
component
removal](5cfcbf47ed/examples/window/screenshot.rs (L38)).
I believe it should, so change it to react to
`RemovedComponents<CursorIcon>`. (a suggestion)
2. Use `get_single` for window.
## Testing
- run screenshot example
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Improve robustness of state transitions. Currently events that should
be scoped to a specific state can leak between state scopes since events
live for two ticks.
- See https://github.com/bevyengine/bevy/issues/15072
## Solution
- Allow registering state scoped events that will be automatically
cleared when exiting a state. This is *most of the time* not obviously
useful, but enables users to write correct code that will avoid/reduce
edge conditions (such as systems that aren't state scoped polling for a
state scoped event and having unintended side effects outside a specific
state instance).
## Testing
Did not test.
---
## Showcase
Added state scoped events that will be automatically cleared when
exiting a state. Useful when you want to guarantee clean state
transitions.
Normal way to add an event:
```rust
fn setup(app: &mut App) {
app.add_event::<MyGameEvent>();
}
```
Add a state-scoped event (**NEW**):
```rust
fn setup(app: &mut App) {
app.add_state_scoped_event::<MyGameEvent>(GameState::Play);
}
```
# Objective
Smaller scoped version of #13375 without the `_mut` variants which
currently have unsoundness issues.
## Solution
Same as #13375, but without the `_mut` variants.
## Testing
- The same test from #13375 is reused.
---
## Migration Guide
- Renamed `FilteredEntityRef::components` to
`FilteredEntityRef::accessed_components` and
`FilteredEntityMut::components` to
`FilteredEntityMut::accessed_components`.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: Periwink <charlesbour@gmail.com>
# Objective
Some of the new compile error messages are a little unclear (at least to
me). For example:
```
error[E0277]: `tests::foo::Bar` can not be created through reflection
--> crates/bevy_reflect/src/lib.rs:679:18
|
679 | #[derive(Reflect)]
| ^^^^^^^ the trait `from_reflect::FromReflect` is not implemented for `tests::foo::Bar`
|
= note: consider annotating `tests::foo::Bar` with `#[derive(Reflect)]` or `#[derive(FromReflect)]`
```
While the annotation makes it clear that `FromReflect` is missing, it's
not very clear from the main error message.
My IDE lists errors with only their message immediately present:
<p align="center">
<img width="700" alt="Image of said IDE listing errors with only their
message immediately present. These errors are as follows:
\"`tests::foo::Bar` can not be created through reflection\", \"The trait
bound `tests::foo::Bar: RegisterForReflection` is not satisfied\", and
\"The trait bound `tests::foo::Bar: type_info::MaybeTyped` is not
satisfied\""
src="https://github.com/user-attachments/assets/42c24051-9e8e-4555-8477-51a9407446aa">
</p>
This makes it hard to tell at a glance why my code isn't compiling.
## Solution
Updated all `on_unimplemented` attributes in `bevy_reflect` to mention
the relevant trait—either the actual trait or the one users actually
need to implement—as well as a small snippet of what not implementing
them means.
For example, failing to implement `TypePath` now mentions missing a
`TypePath` implementation. And failing to implement `DynamicTypePath`
now also mentions missing a `TypePath` implementation, since that's the
actual trait users need to implement (i.e. they shouldn't implement
`DynamicTypePath` directly).
Lastly, I also added some missing `on_unimplemented` attributes for
`MaybeTyped` and `RegisterForReflection` (which you can see in the image
above).
Here's how this looks in my IDE now:
<p align="center">
<img width="700" alt="Similar image as before showing the errors listed
by the IDE. This time the errors read as follows: \"`tests::foo::Bar`
does not implement `FromReflect` so cannot be reified through
reflection\", \"`tests::foo::Bar` does not implement
`GetTypeRegistration` so cannot be registered for reflection\", and
\"`tests::foo::Bar` does not implement `Typed` so cannot provide static
type information\""
src="https://github.com/user-attachments/assets/f6f8501f-0450-4f78-b84f-00e7a18d0533">
</p>
## Testing
You can test by adding the following code and verifying the compile
errors are correct:
```rust
#[derive(Reflect)]
struct Foo(Bar);
struct Bar;
```
# Objective
`ExtractedUiMaterialNode` is still walking the whole `UiStack`.
more info: https://github.com/bevyengine/bevy/pull/9853
## Solution
Retrieve the `stack_index` from the `Node` component instead.
Also changed the `stack_index` field of `ExtractedUiMaterialNode` to
`u32`.
# Objective
Make choosing of diffuse indirect lighting explicit, instead of using
numerical conditions like `all(indirect_light == vec3(0.0f))`, as using
that may lead to unwanted light leakage.
## Solution
Use an explicit `found_diffuse_indirect` condition to indicate the found
indirect lighting source.
## Testing
I have tested examples `lightmaps`, `irradiance_volumes` and
`reflection_probes`, there are no visual changes. For further testing,
consider a "cave" scene with lightmaps and irradiance volumes. In the
cave there are some purly dark occluded area, those dark area will
sample the irradiance volume, and that is easy to leak light.
Hello,
I'd like to contribute to this project by adding some useful constants
and improving the documentation for the AspectRatio struct. Here's a
summary of the changes I've made:
1. Added new constants for common aspect ratios:
- SIXTEEN_NINE (16:9)
- FOUR_THREE (4:3)
- ULTRAWIDE (21:9)
2. Enhanced the overall documentation:
- Improved module-level documentation with an overview and use cases
- Expanded explanation of the AspectRatio struct with examples
- Added detailed descriptions and examples for all methods (both
existing and new)
- Included explanations for the newly introduced constant values
- Added clarifications for From trait implementations
These changes aim to make the AspectRatio API more user-friendly and
easier to understand. The new constants provide convenient access to
commonly used aspect ratios, which I believe will be helpful in many
scenarios.
---------
Co-authored-by: Gonçalo Rica Pais da Silva <bluefinger@gmail.com>
Co-authored-by: Lixou <82600264+DasLixou@users.noreply.github.com>
# Objective
- Fixes#15060
## Solution
- Added `IdentityAssetTransformer<A>` which is an `AssetTransformer`
which infallibly returns the input `Asset` unmodified.
- Replaced `LoadAndSave` and `LoadAndSaveSettings` with type definitions
linking back to `LoadTransformAndSave` and
`LoadTransformAndSaveSettings` respectively.
- Marked `LoadAndSave` and `LoadAndSaveSettings` as depreciated with a
migration guide included, hinting to the user to use the underlying type
instead.
## Testing
- Ran CI locally
---
## Migration Guide
- Replace `LoadAndSave<L, S>` with `LoadTransformAndSave<L,
IdentityAssetTransformer<<L as AssetLoader>::Asset>, S>`
- Replace `LoadAndSaveSettings<L, S>` with
`LoadTransformAndSaveSettings<L, (), S>`
# Objective
- Improve the ergonomics of managing states.
## Solution
- Add `set_state` extension method to `Commands` so you don't need to
type out `ResMut<NextState<S>>` to update a state. It also reduces
system parameter list size when you already have `Commands`.
- I only updated a couple examples to showcase how it can be used. There
*is* a potential perf cost to introducing `Commands` so this method
shouldn't necessarily be used everywhere.
## Testing
- Tested the updated examples: `game_menu` and `alien_cake_addict`.
---
## Showcase
Add `Commands::set_state` method for easily updating states.
Set directly:
```rust
fn go_to_game(mut game_state: ResMut<NextState<GameState>>) {
game_state.set(GameState::Play);
}
```
Set with commands (**NEW**):
```rust
fn go_to_game(mut commands: Commands) {
commands.set_state(GameState::Play);
}
```
Adopted PR from dmlary, all credit to them!
https://github.com/bevyengine/bevy/pull/9915
Original description:
# Objective
The default value for `near` in `OrthographicProjection` should be
different for 2d & 3d.
For 2d using `near = -1000` allows bevy users to build up scenes using
background `z = 0`, and foreground elements `z > 0` similar to css.
However in 3d `near = -1000` results in objects behind the camera being
rendered. Using `near = 0` works for 3d, but forces 2d users to assign
`z <= 0` for rendered elements, putting the background at some arbitrary
negative value.
There is no common value for `near` that doesn't result in a footgun or
usability issue for either 2d or 3d, so they should have separate
values.
There was discussion about other options in the discord
[0](https://discord.com/channels/691052431525675048/1154114310042292325),
but splitting `default()` into `default_2d()` and `default_3d()` seemed
like the lowest cost approach.
Related/past work https://github.com/bevyengine/bevy/issues/9138,
https://github.com/bevyengine/bevy/pull/9214,
https://github.com/bevyengine/bevy/pull/9310,
https://github.com/bevyengine/bevy/pull/9537 (thanks to @Selene-Amanita
for the list)
## Solution
This commit splits `OrthographicProjection::default` into `default_2d`
and `default_3d`.
## Migration Guide
- In initialization of `OrthographicProjection`, change `..default()` to
`..OrthographicProjection::default_2d()` or
`..OrthographicProjection::default_3d()`
Example:
```diff
--- a/examples/3d/orthographic.rs
+++ b/examples/3d/orthographic.rs
@@ -20,7 +20,7 @@ fn setup(
projection: OrthographicProjection {
scale: 3.0,
scaling_mode: ScalingMode::FixedVertical(2.0),
- ..default()
+ ..OrthographicProjection::default_3d()
}
.into(),
transform: Transform::from_xyz(5.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
```
---------
Co-authored-by: David M. Lary <dmlary@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Kind of confused why this wasn't breaking for me pre-`0.15-dev` since
nothing obvious seems to have changed in `wgpu` upstream, but this fixes
it and ensures that we return the correct sample type re: the actual
device.
# Objective
Simplify `pick_rounded_rect` with multiple `if` statements to make it
more readable and efficient([Godbolt
link](https://godbolt.org/z/W5vPEvT5c)).
Co-authored-by: WX\shixi <shixi1@cnwxsoft.com>
# Objective
We should attempt to document the entirety of bevy_assets. `AssetMode`
is missing docs explaining what it is, how it's used and why it exists.
## Solution
Add docs, focusing on the context in
https://github.com/bevyengine/bevy/issues/10157.
# Objective
Fixes: https://github.com/bevyengine/bevy/issues/14515
## Solution
Sorts the iterator with itertools' sorted_by function. This is required
given that 'self.entries' is an immutable &[Box<dyn PartialReflect]
which also doesn't implement Clone or Copy.
## Testing
The modifications passed the unit testing only after they were edited to
ensure that the items were in alphabetical order.
I haven't checked for performance implications.
Adds some methods to assist in building `ShaderStorageBuffer` without
using `bytemuck`. We keep the `&[u8]` constructors since this is still
modeled as a thin wrapper around the buffer descriptor, but should make
it easier to interact with at the cost of an extra allocation in the
`ShaderType` path for the buffer writer.
Follow up from #14663
# Objective
`EntityHash` and related types were moved from `bevy_utils` to
`bevy_ecs` in #11498, but seemed to have been accidentally reintroduced
a week later in #11707.
## Solution
Remove the old leftover code.
---
## Migration Guide
- Uses of `bevy::utils::{EntityHash, EntityHasher, EntityHashMap,
EntityHashSet}` now have to be imported from `bevy::ecs::entity`.
# Objective
It's possible to create UB using an implementation of `QueryFilter` that
performs mutable access, but that does not violate any documented safety
invariants.
This code:
```rust
#[derive(Component)]
struct Foo(usize);
// This derive is a simple way to get a valid WorldQuery impl. The QueryData impl isn't used.
#[derive(QueryData)]
#[query_data(mutable)]
struct BadFilter<'w> {
foo: &'w mut Foo,
}
impl QueryFilter for BadFilter<'_> {
const IS_ARCHETYPAL: bool = false;
unsafe fn filter_fetch(
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
) -> bool {
// SAFETY: fetch and filter_fetch have the same safety requirements
let f: &mut usize = &mut unsafe { Self::fetch(fetch, entity, table_row) }.foo.0;
println!("Got &mut at {f:p}");
true
}
}
let mut world = World::new();
world.spawn(Foo(0));
world.run_system_once(|query: Query<&Foo, BadFilter>| {
let f: &usize = &query.iter().next().unwrap().0;
println!("Got & at {f:p}");
query.iter().next().unwrap();
println!("Still have & at {f:p}");
});
```
prints:
```
Got &mut at 0x1924b92dfb0
Got & at 0x1924b92dfb0
Got &mut at 0x1924b92dfb0
Still have & at 0x1924b92dfb0
```
Which means it had an `&` and `&mut` alive at the same time.
The only `unsafe` there is around `Self::fetch`, but I believe that call
correctly upholds the safety invariant, and matches what `Added` and
`Changed` do.
## Solution
Make `QueryFilter` an unsafe trait and document the requirement that the
`WorldQuery` implementation be read-only.
## Migration Guide
`QueryFilter` is now an `unsafe trait`. If you were manually
implementing it, you will need to verify that the `WorldQuery`
implementation is read-only and then add the `unsafe` keyword to the
`impl`.
Since `StandardMaterial::emissive_exposure_weight` does not get packed
into the gbuffer in the deferred case, unpacking uses an implicit
default value for emissive's alpha channel.
This resulted in divergent behavior between the forward and deferred
renderers when using standard materials with default
emissive_exposure_weight, this value defaulting to `0.0` in the forward
case and `1.0` in the other.
This patch changes the implicit value in the deferred case to `0.0` in
order to match the behavior of the forward renderer. However, this still
does not solve the case where `emissive_exposure_weight` is not `0.0`.
# Objective
The `ser` and `de` modules in `bevy_reflect/serde` are very long and
difficult to navigate.
## Solution
Refactor both modules into many smaller modules that each have a single
primary focus (i.e. a `structs` module that only handles struct
serialization/deserialization).
I chose to keep the `ser` and `de` modules separate. We could have
instead broken it up kind (e.g. lists, maps, etc.), but I think this is
a little cleaner. Serialization and deserialization, while related, can
be very different. So keeping them separated makes sense for
organizational purposes.
That being said, if people disagree and think we should structure this a
different way, I am open to changing it.
Note that this PR's changes are mainly structural. There are a few
places I refactored code to reduce duplication and to make things a bit
cleaner, but these are largely cosmetic and shouldn't have any impact on
behavior.
### Other Details
This PR also hides a lot of the internal logic from being exported.
These were originally public, but it's unlikely they really saw any use
outside of these modules. In fact, you don't really gain anything by
using them outside of this module either.
By privatizing these fields and items, we also set ourselves up for more
easily changing internal logic around without involving a breaking
change.
I also chose not to mess around with tests since that would really blow
up the diff haha.
## Testing
You can test locally by running:
```
cargo test --package bevy_reflect --all-features
```
---
## Migration Guide
The fields on `ReflectSerializer` and `TypedReflectSerializer` are now
private. To instantiate, the corresponding constructor must be used:
```rust
// BEFORE
let serializer = ReflectSerializer {
value: &my_value,
registry: &type_registry,
};
// AFTER
let serializer = ReflectSerializer::new(&my_value, &type_registry);
```
Additionally, the following types are no longer public:
- `ArraySerializer`
- `EnumSerializer`
- `ListSerializer`
- `MapSerializer`
- `ReflectValueSerializer` (fully removed)
- `StructSerializer`
- `TupleSerializer`
- `TupleStructSerializer`
As well as the following traits:
- `DeserializeValue` (fully removed)
### Builder changes
- Increased meshlet max vertices/triangles from 64v/64t to 255v/128t
(meshoptimizer won't allow 256v sadly). This gives us a much greater
percentage of meshlets with max triangle count (128). Still not perfect,
we still end up with some tiny <=10 triangle meshlets that never really
get simplified, but it's progress.
- Removed the error target limit. Now we allow meshoptimizer to simplify
as much as possible. No reason to cap this out, as the cluster culling
code will choose a good LOD level anyways. Again leads to higher quality
LOD trees.
- After some discussion and consulting the Nanite slides again, changed
meshlet group error from _adding_ the max child's error to the group
error, to doing `group_error = max(group_error, max_child_error)`. Error
is already cumulative between LODs as the edges we're collapsing during
simplification get longer each time.
- Bumped the 65% simplification threshold to allow up to 95% of the
original geometry (e.g. accept simplification as valid even if we only
simplified 5% of the triangles). This gives us closer to
log2(initial_meshlet_count) LOD levels, and fewer meshlet roots in the
DAG.
Still more work to be done in the future here. Maybe trying METIS for
meshlet building instead of meshoptimizer.
Using ~8 clusters per group instead of ~4 might also make a big
difference. The Nanite slides say that they have 8-32 meshlets per
group, suggesting some kind of heuristic. Unfortunately meshopt's
compute_cluster_bounds won't work with large groups atm
(https://github.com/zeux/meshoptimizer/discussions/750#discussioncomment-10562641)
so hard to test.
Based on discussion from
https://github.com/bevyengine/bevy/discussions/14998,
https://github.com/zeux/meshoptimizer/discussions/750, and discord.
### Runtime changes
- cluster:triangle packed IDs are now stored 25:7 instead of 26:6 bits,
as max triangles per cluster are now 128 instead of 64
- Hardware raster now spawns 128 * 3 vertices instead of 64 * 3 vertices
to account for the new max triangles limit
- Hardware raster now outputs NaN triangles (0 / 0) instead of
zero-positioned triangles for extra vertex invocations over the cluster
triangle count. Shouldn't really be a difference idt, but I did it
anyways.
- Software raster now does 128 threads per workgroup instead of 64
threads. Each thread now loads, projects, and caches a vertex (vertices
0-127), and then if needed does so again (vertices 128-254). Each thread
then rasterizes one of 128 triangles.
- Fixed a bug with `needs_dispatch_remap`. I had the condition backwards
in my last PR, I probably committed it by accident after testing the
non-default code path on my GPU.
# Objective
A previous issue describes the same problem: #14248.
This particular link was seemingly missed by #14276.
## Solution
- Search repo for `bevyengine.org/learn/errors/#`
- Remove `#`
- Verify link goes to right place
# Objective
- Crate-level prelude modules, such as `bevy_ecs::prelude`, are plagued
with inconsistency! Let's fix it!
## Solution
Format all preludes based on the following rules:
1. All preludes should have brief documentation in the format of:
> The _name_ prelude.
>
> This includes the most common types in this crate, re-exported for
your convenience.
2. All documentation should be outer, not inner. (`///` instead of
`//!`.)
3. No prelude modules should be annotated with `#[doc(hidden)]`. (Items
within them may, though I'm not sure why this was done.)
## Testing
- I manually searched for the term `mod prelude` and updated all
occurrences by hand. 🫠
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- `CursorIcon` had derived `Reflect`, but it wasn't registered
## Solution
- Use `register_type` on it
- I also moved the cursor code to it's own plugin because there was
starting to be too much cursor code outside the cursor file.
## Testing
- window_settings example still works with the custom cursor
# Objective
#14957 added the `pick_rounded_rect` function to `bevy_ui` in the
`picking_backend` module, which is gated behind the `bevy_picking`
feature. This function is used in that module, as well as in the `focus`
module. The latter usage is not gated behind the `bevy_picking` feature,
causing a compile error when the feature is disabled.
## Solution
Move the `pick_rounded_rect` function out of the `picking_backend`
module, as it does not depend on anything defined in that module. I put
it in `lib.rs` but it could reasonably be moved somewhere else instead.
## Testing
Encountered this compile error in a project and confirmed that this
patch fixes it.
# Objective
Fixes#13479
This also fixes the gaps you can sometimes observe in outlines
(screenshot from main, not this PR):
<img width="636" alt="outline-gaps"
src="https://github.com/user-attachments/assets/c11dae24-20f5-4aea-8ffc-1894ad2a2b79">
The outline around the last item in each section has vertical gaps.
## Solution
Draw the outlines with corner radius using the existing border rendering
for uinodes. The outline radius is very simple to calculate. We just
take the computed border radius of the node, and if it's greater than
zero, add it to the distance from the edge of the node to the outer edge
of the node's outline.
---
## Showcase
<img width="634" alt="outlines-radius"
src="https://github.com/user-attachments/assets/1ecda26c-65c5-41ef-87e4-5d9171ddc3ae">
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
Correctly order picking events. Resolves
https://github.com/bevyengine/bevy/issues/5984.
## Solution
Event ordering [very long standing
problem](https://github.com/aevyrie/bevy_mod_picking/issues/294) with
mod picking, stemming from two related issues. The first problem was
that `Pointer<T>` events of different types couldn't be ordered, but we
have already gotten around that in the upstream by switching to
observers. Since observers run in the order they are triggered, this
isn't an issue.
The second problem was that the underlying event streams that picking
uses to create it's pointer interaction events *also* lacked ordering,
and the systems that generated the points couldn't interleave events.
This PR fixes that by unifying the event streams and integrating the
various interaction systems.
The concrete changes are as follows:
+ `bevy_winit::WinitEvent` has been moved to `bevy_window::WindowEvent`.
This provides a unified (and more importantly, *ordered*) input stream
for both `bevy_window` and `bevy_input` events.
+ Replaces `InputMove` and `InputPress` with `PointerInput`, a new
unified input event which drives picking and interaction. This event is
built to have drop-in forward compatibility with [winit's upcoming
pointer abstraction](https://github.com/rust-windowing/winit/pull/3876).
I have added code to emulate it using the current winit input
abstractions, but this entire thing will be much more robust when it
lands.
+ Rolls `pointer_events` `send_click_and_drag_events` and
`send_drag_over_events` into a single system, which operates directly on
`PointerEvent` and triggers observers as output.
The PR also improves docs and takes the opportunity to
refactor/streamline the pointer event dispatch logic.
## Status & Testing
This PR is now feature complete and documented. While it is
theoretically possible to add unit tests for the ordering, building the
picking mocking for that will take a little while.
Feedback on the chosen ordering of events is within-scope.
## Migration Guide
For users switching from `bevy_mod_picking` to `bevy_picking`:
+ Instead of adding an `On<T>` component, use `.observe(|trigger:
Trigger<T>|)`. You may now apply multiple handlers to the same entity
using this command.
+ Pointer interaction events now have semi-deterministic ordering which
(more or less) aligns with the order of the raw input stream. Consult
the docs on `bevy_picking::event::pointer_events` for current
information. You may need to adjust your event handling logic
accordingly.
+ `PointerCancel` has been replaced with `Pointer<Cancled>`, which now
has the semantics of an OS touch pointer cancel event.
+ `InputMove` and `InputPress` have been merged into `PointerInput`. The
use remains exactly the same.
+ Picking interaction events are now only accessible through observers,
and no `EventReader`. This functionality may be re-implemented later.
For users of `bevy_winit`:
+ The event `bevy_winit::WinitEvent` has moved to
`bevy_window::WindowEvent`. If this was the only thing you depended on
`bevy_winit` for, you should switch your dependency to `bevy_window`.
+ `bevy_window` now depends on `bevy_input`. The dependencies of
`bevy_input` are a subset of the existing dependencies for `bevy_window`
so this should be non-breaking.
# Objective
Fixes#15032
## Solution
Reimplement support for the `flip_x` and `flip_y` fields.
This doesn't flip the border geometry, I'm not really sure whether that
is desirable or not.
Also fixes a bug that was causing the side and center slices to tile
incorrectly.
### Testing
```
cargo run --example ui_texture_slice_flip_and_tile
```
## Showcase
<img width="787" alt="nearest"
src="https://github.com/user-attachments/assets/bc044bae-1748-42ba-92b5-0500c87264f6">
With tiling need to use nearest filtering to avoid bleeding between the
slices.
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- follow of #14049 ,we could use it on our Parallel Iterator,this pr
also unified the used function in both regular iter and parallel
iterations.
## Performance
![image](https://github.com/user-attachments/assets/cba700bc-169c-4b58-b504-823bdca8ec05)
no performance regression for regular itertaion
3.5X faster in hybrid parallel iteraion,this number is far greater than
the benefits obtained in regular iteration(~1.81) because mutable
iterations on continuous memory can effectively reduce the cost of
mataining core cache coherence
# Objective
As discussed in https://github.com/bevyengine/bevy/issues/7386, system
order ambiguities within `DefaultPlugins` are a source of bugs in the
engine and badly pollute diagnostic output for users.
We should eliminate them!
This PR is an alternative to #15027: with all external ambiguities
silenced, this should be much less prone to merge conflicts and the test
output should be much easier for authors to understand.
Note that system order ambiguities are still permitted in the
`RenderApp`: these need a bit of thought in terms of how to test them,
and will be fairly involved to fix. While these aren't *good*, they'll
generally only cause graphical bugs, not logic ones.
## Solution
All remaining system order ambiguities have been resolved.
Review this PR commit-by-commit to see how each of these problems were
fixed.
## Testing
`cargo run --example ambiguity_detection` passes with no panics or
logging!
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14593.
## Solution
- Add `ViewportConversionError` and return it from viewport conversion
methods on Camera.
## Testing
- I successfully compiled and ran all changed examples.
## Migration Guide
The following methods on `Camera` now return a `Result` instead of an
`Option` so that they can provide more information about failures:
- `world_to_viewport`
- `world_to_viewport_with_depth`
- `viewport_to_world`
- `viewport_to_world_2d`
Call `.ok()` on the `Result` to turn it back into an `Option`, or handle
the `Result` directly.
---------
Co-authored-by: Lixou <82600264+DasLixou@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
- Fixes#14966
## Solution
- Added a _Performance_ section to the documentation for
`LogPlugin::filter` explaining that long filter strings can degrade
performance and to instead rely on `LogPlugin::level` when possible.
## Testing
- CI passed locally.
# Objective
- Currently we have the `ColorRange` trait to interpolate linearly
between two colors
- It would be cool to have:
1. linear interpolation between n colors where `n >= 1`
2. other kinds of interpolation
## Solution
1. Implement `ColorGradient` which takes `n >= 1` colors and linearly
interpolates between consecutive pairs of them
2. Implement `Curve` intergration for this `ColorGradient` which yields
a curve struct. After that we can apply all of the cool curve adaptors
like `.reparametrize()` and `.map()` to the gradient
## Testing
- Added doc tests
- Added tests
## Showcase
```rust
// let gradient = ColorGradient::new(vec![]).unwrap(); // panic! 💥
let gradient = ColorGradient::new([basic::RED, basic::LIME, basic::BLUE]).expect("non-empty");
let curve = gradient.to_curve();
let brighter_curve = curve.map(|c| c.mix(&basic::WHITE, 0.5));
```
---
Kind of related to
https://github.com/bevyengine/bevy/pull/14971#discussion_r1736337631
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Co-authored-by: Matty <weatherleymatthew@gmail.com>
# Objective
Fixes https://github.com/bevyengine/bevy/issues/14183
## Solution
Reimplement the UI texture atlas slicer using a shader.
The problems with #14183 could be fixed more simply by hacking around
with the coordinates and scaling but that way is very fragile and might
get broken again the next time we make changes to the layout
calculations. A shader based solution is more robust, it's impossible
for gaps to appear between the image slices with these changes as we're
only drawing a single quad.
I've not tried any benchmarks yet but it should much more efficient as
well, in the worst cases even hundreds or thousands of times faster.
Maybe could have used the UiMaterialPipeline. I wrote the shader first
and used fat vertices and then realised it wouldn't work that way with a
UiMaterial. If it's rewritten it so it puts all the slice geometry in
uniform buffer, then it might work? Adding the uniform buffer would
probably make the shader more complicated though, so don't know if it's
even worth it. Instancing is another alternative.
## Testing
The examples are working and it seems to match the old API correctly but
I've not used the texture atlas slicing API for anything before, I
reviewed the PR but that was back in January.
Needs a review by someone who knows the rendering pipeline and wgsl
really well because I don't really have any idea what I'm doing.
# Objective
The `BorderRadius` component shouldn't be required to draw borders for
nodes with sharp corners.
## Solution
Make `BorderRadius` optional in `extract_uinode_borders`'s UI node
query.
# Objective
The `Parent` component holds a reference to the parent entity of the
entity it is inserted onto. The `with_child` function erroneously
forgets to insert this component onto the child entity that it spawns,
causing buggy behaviour when the function is used instead of the other
child-spawning functions.
## Solution
Ensure `with_child` inserts the `Parent` component, the same as all the
other child-spawning functions.
## Testing
Checked before/after with a bevy_ui layout where this patch fixed buggy
behaviour I was seeing in parent/child UI nodes.
# Objective
- Fixes#14969
## Solution
- Added `Deserialize` to the list of reflected traits for `SmolStr`
## Testing
- CI passed locally.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit adds support for *masks* to the animation graph. A mask is a
set of animation targets (bones) that neither a node nor its descendants
are allowed to animate. Animation targets can be assigned one or more
*mask group*s, which are specific to a single graph. If a node masks out
any mask group that an animation target belongs to, animation curves for
that target will be ignored during evaluation.
The canonical use case for masks is to support characters holding
objects. Typically, character animations will contain hand animations in
the case that the character's hand is empty. (For example, running
animations may close a character's fingers into a fist.) However, when
the character is holding an object, the animation must be altered so
that the hand grips the object.
Bevy currently has no convenient way to handle this. The only workaround
that I can see is to have entirely separate animation clips for
characters' hands and bodies and keep them in sync, which is burdensome
and doesn't match artists' expectations from other engines, which all
effectively have support for masks. However, with mask group support,
this task is simple. We assign each hand to a mask group and parent all
character animations to a node. When a character grasps an object in
hand, we position the fingers as appropriate and then enable the mask
group for that hand in that node. This allows the character's animations
to run normally, while the object remains correctly attached to the
hand.
Note that even with this PR, we won't have support for running separate
animations for a character's hand and the rest of the character. This is
because we're missing additive blending: there's no way to combine the
two masked animations together properly. I intend that to be a follow-up
PR.
The major engines all have support for masks, though the workflow varies
from engine to engine:
* Unity has support for masks [essentially as implemented here], though
with layers instead of a tree. However, when using the Mecanim
("Humanoid") feature, precise control over bones is lost in favor of
predefined muscle groups.
* Unreal has a feature named [*layered blend per bone*]. This allows for
separate blend weights for different bones, effectively achieving masks.
I believe that the combination of blend nodes and masks make Bevy's
animation graph as expressible as that of Unreal, once we have support
for additive blending, though you may have to use more nodes than you
would in Unreal. Moreover, separating out the concepts of "blend weight"
and "which bones this node applies to" seems like a cleaner design than
what Unreal has.
* Godot's `AnimationTree` has the notion of [*blend filters*], which are
essentially the same as masks as implemented in this PR.
Additionally, this patch fixes a bug with weight evaluation whereby
weights weren't properly propagated down to grandchildren, because the
weight evaluation for a node only checked its parent's weight, not its
evaluated weight. I considered submitting this as a separate PR, but
given that this PR refactors that code entirely to support masks and
weights under a unified "evaluated node" concept, I simply included the
fix here.
A new example, `animation_masks`, has been added. It demonstrates how to
toggle masks on and off for specific portions of a skin.
This is part of #14395, but I'm going to defer closing that issue until
we have additive blending.
[essentially as implemented here]:
https://docs.unity3d.com/560/Documentation/Manual/class-AvatarMask.html
[*layered blend per bone*]:
https://dev.epicgames.com/documentation/en-us/unreal-engine/using-layered-animations-in-unreal-engine
[*blend filters*]:
https://docs.godotengine.org/en/stable/tutorials/animation/animation_tree.html
## Migration Guide
* The serialized format of animation graphs has changed with the
addition of animation masks. To upgrade animation graph RON files, add
`mask` and `mask_groups` fields as appropriate. (They can be safely set
to zero.)
# Objective
`resolve_outlines_system` wasn't updated when multi-window support was
added and it always uses the size of the primary window when resolving
viewport coords, regardless of the layout's camera target.
Fixes#14945
## Solution
It's awkward to get the viewport size of the target for an individual
node without walking the tree or adding extra fields to `Node`, so I
removed `resolve_outlines_system` and instead the outline values are
updated in `ui_layout_system`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Make the documentation for `SystemParamBuilder` nicer by combining the
tuple implementations into a single line of documentation.
## Solution
Use `#[doc(fake_variadic)]` for `SystemParamBuilder` tuple impls.
![image](https://github.com/user-attachments/assets/b4665861-c405-467f-b30b-82b4b1d99bf7)
(This got missed originally because #14050 and #14703 were open at the
same time.)
Adds a new `Handle<Storage>` asset type that can be used as a render
asset, particularly for use with `AsBindGroup`.
Closes: #13658
# Objective
Allow users to create storage buffers in the main world without having
to access the `RenderDevice`. While this resource is technically
available, it's bad form to use in the main world and requires mixing
rendering details with main world code. Additionally, this makes storage
buffers easier to use with `AsBindGroup`, particularly in the following
scenarios:
- Sharing the same buffers between a compute stage and material shader.
We already have examples of this for storage textures (see game of life
example) and these changes allow a similar pattern to be used with
storage buffers.
- Preventing repeated gpu upload (see the previous easier to use `Vec`
`AsBindGroup` option).
- Allow initializing custom materials using `Default`. Previously, the
lack of a `Default` implement for the raw `wgpu::Buffer` type made
implementing a `AsBindGroup + Default` bound difficult in the presence
of buffers.
## Solution
Adds a new `Handle<Storage>` asset type that is prepared into a
`GpuStorageBuffer` render asset. This asset can either be initialized
with a `Vec<u8>` of properly aligned data or with a size hint. Users can
modify the underlying `wgpu::BufferDescriptor` to provide additional
usage flags.
## Migration Guide
The `AsBindGroup` `storage` attribute has been modified to reference the
new `Handle<Storage>` asset instead. Usages of Vec` should be converted
into assets instead.
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
- Avoid cloning the `CosmicBuffer` every time you create a new text
measurement.
## Solution
- Inject a buffer query when calculating layout so existing buffers can
be reused.
## Testing
- I tested the `text`, `text_debug`, and `text_wrap_debug` examples.
- I did not do a performance test.
Fixes#14993 (maybe). Adds a system ordering constraint that was missed
in the refactor in #14833. The theory here is that the single threaded
forces a topology that causes the prepare system to run before
`prepare_windows` in a way that causes issues. For whatever reason, this
appears to be unlikely when multi-threading is enabled.
# Objective
* Fixes https://github.com/bevyengine/bevy/issues/14889
## Solution
Exposes `bevy_animation::{animatable, graph, transition}` to the world.
## Testing
- Did you test these changes? If so, how?
- These changes do not need testing, as they do not modify/add/remove
any functionality.
- ~~Are there any parts that need more testing?~~
- ~~How can other people (reviewers) test your changes? Is there
anything specific they need to know?~~
- ~~If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?~~
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The `reflect` module in `bevy_state` is gated behind the `bevy_reflect`
feature, but the type exports from that module in the crate prelude are
erroneously gated behind the `bevy_app` feature, causing a compile error
when the `bevy_reflect` feature is disabled, but the `bevy_app` feature
is enabled.
## Solution
Change the feature gate to `bevy_reflect`.
## Testing
- Discovered by depending on `bevy_state` with `default-features =
false, features = ["bevy_app"]`
- Tested by running `cargo check -p bevy_state --no-default-features
--features bevy_app`
# Objective
- Fixes#14974
## Solution
- Replace all* instances of `NonZero*` with `NonZero<*>`
## Testing
- CI passed locally.
---
## Notes
Within the `bevy_reflect` implementations for `std` types,
`impl_reflect_value!()` will continue to use the type aliases instead,
as it inappropriately parses the concrete type parameter as a generic
argument. If the `ZeroablePrimitive` trait was stable, or the macro
could be modified to accept a finite list of types, then we could fully
migrate.
# Objective
`bevy_animation` imports a lot of items - and it uses a very
inconsistent code style to do so.
## Solution
Changes the offending `use` statements to be more consistent across the
crate.
## Testing
- Did you test these changes? If so, how?
- No testing is needed beyond lint checks, and those finished
successfully.
- ~~Are there any parts that need more testing?~~
- ~~How can other people (reviewers) test your changes? Is there
anything specific they need to know?~~
- ~~If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?~~
# Objective
- There's one occurence of `CowArc::Borrow` that wraps '&'static str`
## Solution
- Replaces it with `CowArc::Static`. I don't think this change is
important but I can't unsee it:)
## Testing
- `cargo check` compiles fine
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14961
## Solution
- Check that the archetypes don't contain any other observed components
before unsetting their flags
## Testing
- I added a regression test: `observer_despawn_archetype_flags`
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14975
## Solution
- Replace usages of `bevy_utils::CowArc` with `atomicow::CowArc`
- Remove bevy_utils::CowArc
## Testing
- `bevy_asset` test suite continues to pass.
---
## Migration Guide
`bevy_utils::CowArc` has moved to a new crate called
[atomicow](https://crates.io/crates/atomicow).
# Objective
- Add gizmos integration for the new `Curve` things in the math lib
## Solution
- Add the following methods
- `curve_2d(curve, sample_times, color)`
- `curve_3d(curve, sample_times, color)`
- `curve_gradient_2d(curve, sample_times_with_colors)`
- `curve_gradient_3d(curve, sample_times_with_colors)`
## Testing
- I added examples of the 2D and 3D variants of the gradient curve
gizmos to the gizmos examples.
## Showcase
### 2D
![image](https://github.com/user-attachments/assets/01a75706-a7b4-4fc5-98d5-18018185c877)
```rust
let domain = Interval::EVERYWHERE;
let curve = function_curve(domain, |t| Vec2::new(t, (t / 25.0).sin() * 100.0));
let resolution = ((time.elapsed_seconds().sin() + 1.0) * 50.0) as usize;
let times_and_colors = (0..=resolution)
.map(|n| n as f32 / resolution as f32)
.map(|t| (t - 0.5) * 600.0)
.map(|t| (t, TEAL.mix(&HOT_PINK, (t + 300.0) / 600.0)));
gizmos.curve_gradient_2d(curve, times_and_colors);
```
### 3D
![image](https://github.com/user-attachments/assets/3fd23983-1ec9-46cd-baed-5b5e2dc935d0)
```rust
let domain = Interval::EVERYWHERE;
let curve = function_curve(domain, |t| {
(Vec2::from((t * 10.0).sin_cos())).extend(t - 6.0)
});
let resolution = ((time.elapsed_seconds().sin() + 1.0) * 100.0) as usize;
let times_and_colors = (0..=resolution)
.map(|n| n as f32 / resolution as f32)
.map(|t| t * 5.0)
.map(|t| (t, TEAL.mix(&HOT_PINK, t / 5.0)));
gizmos.curve_gradient_3d(curve, times_and_colors);
```
# Objective
With the current implementation of `Plane3d` gizmos, it's really hard to
get a good feeling for big planes. Usually I tend to add more axes as a
user but that doesn't scale well and is pretty wasteful. It's hard to
recognize the plane in the distance here. Especially if there would've
been other rendered objects in the scene
![image](https://github.com/user-attachments/assets/b65b7015-c08c-46d7-aa27-c7c0d49b2021)
## Solution
- Since we got grid gizmos in the mean time, I went ahead and just
reused them here.
## Testing
I added an instance of the new `Plane3D` to the `3d_gizmos.rs` example.
If you want to look at it you need to look around a bit. I didn't
position it in the center since that was too crowded already.
---
## Showcase
![image](https://github.com/user-attachments/assets/e4982afe-7296-416c-9801-7dd85cd975c1)
## Migration Guide
The optional builder methods on
```rust
gizmos.primitive_3d(&Plane3d { }, ...);
```
changed from
- `segment_length`
- `segment_count`
- `axis_count`
to
- `cell_count`
- `spacing`
# Objective
This moves the default `LogPlugin` filter to be a public constant so
that it can be updated and referenced from outside code without changes
across releases:
```
fn main() {
App::new().add_plugins(
DefaultPlugins
.set(bevy::log::LogPlugin {
filter: format!("{},mylogs=error", bevy::log::LogPlugin::DEFAULT_FILTER),
..default()
})).run();
}
```
## Testing
Tested with `cargo run -p ci`
# Objective
Allow `SystemParamBuilder` implementations for custom system parameters
created using `#[derive(SystemParam)]`.
## Solution
Extend the derive macro to accept a `#[system_param(builder)]`
attribute. When present, emit a builder type with a field corresponding
to each field of the param.
## Example
```rust
#[derive(SystemParam)]
#[system_param(builder)]
struct CustomParam<'w, 's> {
query: Query<'w, 's, ()>,
local: Local<'s, usize>,
}
let system = (CustomParamBuilder {
local: LocalBuilder(100),
query: QueryParamBuilder::new(|builder| {
builder.with::<A>();
}),
},)
.build_state(&mut world)
.build_system(|param: CustomParam| *param.local + param.query.iter().count());
```
# Objective
- Fixes#14841
## Solution
- Compute BufferSlice size manually and use it for comparison in
`TrackedRenderPass`
## Testing
- Gizmo example does not crash with #14721 (without system ordering),
and `slice` computes correct size there
---
## Migration Guide
- `TrackedRenderPass::set_vertex_buffer` function has been modified to
update vertex buffers when the same buffer with the same offset is
provided, but its size has changed. Some existing code may rely on the
previous behavior, which did not update the vertex buffer in this
scenario.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
- Fixes#14860
## Solution
- Added a line of documentation to `FromWorld`'s trait definition
mention the `Default` blanket implementation.
- Added custom documentation to the `from_world` method for the
`Default` blanket implementation. This ensures when inspecting the
`from_world` function within an IDE, the tooltip will explicitly state
the `default()` method will be used for any `Default` types.
## Testing
- CI passes.
# Objective
Since https://github.com/bevyengine/bevy/pull/14731 is merged, it
unblocked a few utility methods for 2D arcs. In 2D the pendant to
`long_arc_3d_between` and `short_arc_3d_between` are missing. Since
`arc_2d` can be a bit hard to use, this PR is trying to plug some holes
in the `arcs` API.
## Solution
Implement
- `long_arc_2d_between(center, from, tp, color)`
- `short_arc_2d_between(center, from, tp, color)`
## Testing
- There are new doc tests
- The `2d_gizmos` example has been extended a bit to include a few more
arcs which can easily be checked with respect to the grid
---
## Showcase
![image](https://github.com/user-attachments/assets/b90ad8b1-86c2-4304-a481-4f9a5246c457)
Code related to the screenshot (from outer = first line to inner = last
line)
```rust
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 80.0, ORANGE_RED);
my_gizmos.short_arc_2d_between(Vec2::ZERO, Vec2::X * 40.0, Vec2::Y * 40.0, ORANGE_RED);
my_gizmos.long_arc_2d_between(Vec2::ZERO, Vec2::X * 20.0, Vec2::Y * 20.0, ORANGE_RED);
```
# Objective
When building a system from `SystemParamBuilder`s and defining the
system as a closure, the compiler should be able to infer the parameter
types from the builder types.
## Solution
Create methods for each arity that take an argument that implements both
`SystemParamFunction` as well as `FnMut(SystemParamItem<P>,...)`. The
explicit `FnMut` constraint will allow the compiler to infer the
necessary higher-ranked lifetimes along with the parameter types.
I wanted to show that this was possible, but I can't tell whether it's
worth the complexity. It requires a separate method for each arity,
which pollutes the docs a bit:
![SystemState build_system
docs](https://github.com/user-attachments/assets/5069b749-7ec7-47e3-a5e4-1a4c78129f78)
## Example
```rust
let system = (LocalBuilder(0u64), ParamBuilder::local::<u64>())
.build_state(&mut world)
.build_system(|a, b| *a + *b + 1);
```
# Objective
- Solves the last bullet in and closes#14319
- Make better use of the `Isometry` types
- Prevent issues like #14655
- Probably simplify and clean up a lot of code through the use of Gizmos
as well (i.e. the 3D gizmos for cylinders circles & lines don't connect
well, probably due to wrong rotations)
## Solution
- go through the `bevy_gizmos` crate and give all methods a slight
workover
## Testing
- For all the changed examples I run `git switch main && cargo rr
--example <X> && git switch <BRANCH> && cargo rr --example <X>` and
compare the visual results
- Check if all doc tests are still compiling
- Check the docs in general and update them !!!
---
## Migration Guide
The gizmos methods function signature changes as follows:
- 2D
- if it took `position` & `rotation_angle` before ->
`Isometry2d::new(position, Rot2::radians(rotation_angle))`
- if it just took `position` before ->
`Isometry2d::from_translation(position)`
- 3D
- if it took `position` & `rotation` before ->
`Isometry3d::new(position, rotation)`
- if it just took `position` before ->
`Isometry3d::from_translation(position)`
# Objective
sending events tends to be low-frequency so ergonomics can be
prioritized over efficiency.
add `Commands::send_event` to send any type of event without needing a
writer in hand.
i don't know how we feel about these kind of ergonomic things, i add
this to all my projects and find it useful. adding `mut
this_particular_event_writer: EventWriter<ThisParticularEvent>` every
time i want to send something is unnecessarily cumbersome.
it also simplifies the "send and receive in the same system" pattern
significantly.
basic example before:
```rs
fn my_func(
q: Query<(Entity, &State)>,
mut damage_event_writer: EventWriter<DamageEvent>,
mut heal_event_writer: EventWriter<HealEvent>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
damage_event_writer.send(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
heal_event_writer.send(HealEvent { entity, heal });
}
}
}
```
basic example after:
```rs
import bevy::ecs::event::SendEventEx;
fn my_func(
mut commands: Commands,
q: Query<(Entity, &State)>,
) {
for (entity, state) in q.iter() {
if let Some(damage) = state.get_damage() {
commands.send_event(DamageEvent { entity, damage });
}
if let Some(heal) = state.get_heal() {
commands.send_event(HealEvent { entity, heal });
}
}
}
```
send/receive in the same system before:
```rs
fn send_and_receive_param_set(
mut param_set: ParamSet<(EventReader<DebugEvent>, EventWriter<DebugEvent>)>,
) {
// We must collect the events to resend, because we can't access the writer while we're iterating over the reader.
let mut events_to_resend = Vec::new();
// This is p0, as the first parameter in the `ParamSet` is the reader.
for event in param_set.p0().read() {
if event.resend_from_param_set {
events_to_resend.push(event.clone());
}
}
// This is p1, as the second parameter in the `ParamSet` is the writer.
for mut event in events_to_resend {
event.times_sent += 1;
param_set.p1().send(event);
}
}
```
after:
```rs
use bevy::ecs::event::SendEventEx;
fn send_via_commands_and_receive(
mut reader: EventReader<DebugEvent>,
mut commands: Commands,
) {
for event in reader.read() {
if event.resend_via_commands {
commands.send_event(DebugEvent {
times_sent: event.times_sent + 1,
..event.clone()
});
}
}
}
```
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
## Introduction
This is the first step in my [Next Generation Scene / UI
Proposal](https://github.com/bevyengine/bevy/discussions/14437).
Fixes https://github.com/bevyengine/bevy/issues/7272#14800.
Bevy's current Bundles as the "unit of construction" hamstring the UI
user experience and have been a pain point in the Bevy ecosystem
generally when composing scenes:
* They are an additional _object defining_ concept, which must be
learned separately from components. Notably, Bundles _are not present at
runtime_, which is confusing and limiting.
* They can completely erase the _defining component_ during Bundle init.
For example, `ButtonBundle { style: Style::default(), ..default() }`
_makes no mention_ of the `Button` component symbol, which is what makes
the Entity a "button"!
* They are not capable of representing "dependency inheritance" without
completely non-viable / ergonomically crushing nested bundles. This
limitation is especially painful in UI scenarios, but it applies to
everything across the board.
* They introduce a bunch of additional nesting when defining scenes,
making them ugly to look at
* They introduce component name "stutter": `SomeBundle { component_name:
ComponentName::new() }`
* They require copious sprinklings of `..default()` when spawning them
in Rust code, due to the additional layer of nesting
**Required Components** solve this by allowing you to define which
components a given component needs, and how to construct those
components when they aren't explicitly provided.
This is what a `ButtonBundle` looks like with Bundles (the current
approach):
```rust
#[derive(Component, Default)]
struct Button;
#[derive(Bundle, Default)]
struct ButtonBundle {
pub button: Button,
pub node: Node,
pub style: Style,
pub interaction: Interaction,
pub focus_policy: FocusPolicy,
pub border_color: BorderColor,
pub border_radius: BorderRadius,
pub image: UiImage,
pub transform: Transform,
pub global_transform: GlobalTransform,
pub visibility: Visibility,
pub inherited_visibility: InheritedVisibility,
pub view_visibility: ViewVisibility,
pub z_index: ZIndex,
}
commands.spawn(ButtonBundle {
style: Style {
width: Val::Px(100.0),
height: Val::Px(50.0),
..default()
},
focus_policy: FocusPolicy::Block,
..default()
})
```
And this is what it looks like with Required Components:
```rust
#[derive(Component)]
#[require(Node, UiImage)]
struct Button;
commands.spawn((
Button,
Style {
width: Val::Px(100.0),
height: Val::Px(50.0),
..default()
},
FocusPolicy::Block,
));
```
With Required Components, we mention only the most relevant components.
Every component required by `Node` (ex: `Style`, `FocusPolicy`, etc) is
automatically brought in!
### Efficiency
1. At insertion/spawn time, Required Components (including recursive
required components) are initialized and inserted _as if they were
manually inserted alongside the given components_. This means that this
is maximally efficient: there are no archetype or table moves.
2. Required components are only initialized and inserted if they were
not manually provided by the developer. For the code example in the
previous section, because `Style` and `FocusPolicy` are inserted
manually, they _will not_ be initialized and inserted as part of the
required components system. Efficient!
3. The "missing required components _and_ constructors needed for an
insertion" are cached in the "archetype graph edge", meaning they aren't
computed per-insertion. When a component is inserted, the "missing
required components" list is iterated (and that graph edge (AddBundle)
is actually already looked up for us during insertion, because we need
that for "normal" insert logic too).
### IDE Integration
The `#[require(SomeComponent)]` macro has been written in such a way
that Rust Analyzer can provide type-inspection-on-hover and `F12` /
go-to-definition for required components.
### Custom Constructors
The `require` syntax expects a `Default` constructor by default, but it
can be overridden with a custom constructor:
```rust
#[derive(Component)]
#[require(
Node,
Style(button_style),
UiImage
)]
struct Button;
fn button_style() -> Style {
Style {
width: Val::Px(100.0),
..default()
}
}
```
### Multiple Inheritance
You may have noticed by now that this behaves a bit like "multiple
inheritance". One of the problems that this presents is that it is
possible to have duplicate requires for a given type at different levels
of the inheritance tree:
```rust
#[derive(Component)
struct X(usize);
#[derive(Component)]
#[require(X(x1))
struct Y;
fn x1() -> X {
X(1)
}
#[derive(Component)]
#[require(
Y,
X(x2),
)]
struct Z;
fn x2() -> X {
X(2)
}
// What version of X is inserted for Z?
commands.spawn(Z);
```
This is allowed (and encouraged), although this doesn't appear to occur
much in practice. First: only one version of `X` is initialized and
inserted for `Z`. In the case above, I think we can all probably agree
that it makes the most sense to use the `x2` constructor for `X`,
because `Y`'s `x1` constructor exists "beneath" `Z` in the inheritance
hierarchy; `Z`'s constructor is "more specific".
The algorithm is simple and predictable:
1. Use all of the constructors (including default constructors) directly
defined in the spawned component's require list
2. In the order the requires are defined in `#[require()]`, recursively
visit the require list of each of the components in the list (this is a
depth Depth First Search). When a constructor is found, it will only be
used if one has not already been found.
From a user perspective, just think about this as the following:
1. Specifying a required component constructor for `Foo` directly on a
spawned component `Bar` will result in that constructor being used (and
overriding existing constructors lower in the inheritance tree). This is
the classic "inheritance override" behavior people expect.
2. For cases where "multiple inheritance" results in constructor
clashes, Components should be listed in "importance order". List a
component earlier in the requirement list to initialize its inheritance
tree earlier.
Required Components _does_ generally result in a model where component
values are decoupled from each other at construction time. Notably, some
existing Bundle patterns use bundle constructors to initialize multiple
components with shared state. I think (in general) moving away from this
is necessary:
1. It allows Required Components (and the Scene system more generally)
to operate according to simple rules
2. The "do arbitrary init value sharing in Bundle constructors" approach
_already_ causes data consistency problems, and those problems would be
exacerbated in the context of a Scene/UI system. For cases where shared
state is truly necessary, I think we are better served by observers /
hooks.
3. If a situation _truly_ needs shared state constructors (which should
be rare / generally discouraged), Bundles are still there if they are
needed.
## Next Steps
* **Require Construct-ed Components**: I have already implemented this
(as defined in the [Next Generation Scene / UI
Proposal](https://github.com/bevyengine/bevy/discussions/14437). However
I've removed `Construct` support from this PR, as that has not landed
yet. Adding this back in requires relatively minimal changes to the
current impl, and can be done as part of a future Construct pr.
* **Port Built-in Bundles to Required Components**: This isn't something
we should do right away. It will require rethinking our public
interfaces, which IMO should be done holistically after the rest of Next
Generation Scene / UI lands. I think we should merge this PR first and
let people experiment _inside their own code with their own Components_
while we wait for the rest of the new scene system to land.
* **_Consider_ Automatic Required Component Removal**: We should
evaluate _if_ automatic Required Component removal should be done. Ex:
if all components that explicitly require a component are removed,
automatically remove that component. This issue has been explicitly
deferred in this PR, as I consider the insertion behavior to be
desirable on its own (and viable on its own). I am also doubtful that we
can find a design that has behavior we actually want. Aka: can we
_really_ distinguish between a component that is "only there because it
was automatically inserted" and "a component that was necessary / should
be kept". See my [discussion response
here](https://github.com/bevyengine/bevy/discussions/14437#discussioncomment-10268668)
for more details.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Pascal Hertleif <killercup@gmail.com>
# Objective
The Android example on Adreno 642L currently crashes on startup.
Previous PRs #14176 and #13323 have adressed this specific crash
occurring on some Adreno GPUs, that fix works as it should but isn't
applied when to the GPU name contains a suffix like in the case of
`642L`.
## Solution
- Amending the logic to filter out any parts of the GPU name not
containing digits thus enabling the fix on `642L`.
## Testing
- Ran the Android example on a Nothing Phone 1. Before this change it
crashed, after it works as intended.
---------
Co-authored-by: Sam Pettersson <sam.pettersson@geoguessr.com>
# Objective
- `Curve<T>` was meant to be object safe, but one of the latest commits
made it not object safe.
- When trying to use `Curve<T>` as `&dyn Curve<T>` this compile error is
raised:
```
error[E0038]: the trait `curve::Curve` cannot be made into an object
--> crates/bevy_math/src/curve/mod.rs:1025:20
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> crates/bevy_math/src/curve/mod.rs:60:8
|
23 | pub trait Curve<T> {
| ----- this trait cannot be made into an object...
...
60 | fn sample_iter(&self, iter: impl IntoIterator<Item = f32>) -> impl Iterator<Item = Option<T>> {
| ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `sample_iter` references an `impl Trait` type in its return type
| |
| ...because method `sample_iter` has generic type parameters
...
```
## Solution
- Making `Curve<T>` object safe again by adding `Self: Sized` to newly
added methods.
## Testing
- Added new test that ensures the `Curve<T>` trait can be made into an
objet.
# Objective
- Fixes#14348
- Fixes#14528
- Less complex (but also likely less performant) alternative to #14611
## Solution
- Add a `is_dense` field flag to `QueryIter` indicating whether it is
dense or not, that is whether it can perform dense iteration or not;
- Check this flag any time iteration over a query is performed.
---
It would be nice if someone could try benching this change to see if it
actually matters.
~Note that this not 100% ready for mergin, since there are a bunch of
safety comments on the use of the various `IS_DENSE` for checks that
still need to be updated.~ This is ready modulo benchmarks
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
when handles for loading assets are dropped, we currently wait until
load is completed before dropping the handle. drop asset-load tasks
immediately
## Solution
- track tasks for loading assets and drop them immediately when all
handles are dropped.
~~- use `join_all` in `gltf_loader.rs` to allow it to yield and be
dropped.~~
doesn't cover all the load apis - for those it doesn't cover the task
will still be detached and will still complete before the result is
discarded.
separated out from #13170
# Objective
Allow dynamic systems to take lists of system parameters whose length is
not known at compile time.
This can be used for building a system that runs a script defined at
runtime, where the script needs a variable number of query parameters.
It can also be used for building a system that collects a list of
plugins at runtime, and provides a parameter to each one.
This is most useful today with `Vec<Query<FilteredEntityMut>>`. It will
be even more useful with `Vec<DynSystemParam>` if #14817 is merged,
since the parameters in the list can then be of different types.
## Solution
Implement `SystemParam` and `SystemParamBuilder` for `Vec` and
`ParamSet<Vec>`.
## Example
```rust
let system = (vec![
QueryParamBuilder::new_box(|builder| {
builder.with::<B>().without::<C>();
}),
QueryParamBuilder::new_box(|builder| {
builder.with::<C>().without::<B>();
}),
],)
.build_state(&mut world)
.build_system(|params: Vec<Query<&mut A>>| {
let mut count: usize = 0;
params
.into_iter()
.for_each(|mut query| count += query.iter_mut().count());
count
});
```
# Objective
- Fixes#14902
- > #14686 Introduced a name clash when using use bevy::prelude::*;
## Solution
- renamed `bevy::picking::events::Drop`
`bevy::picking::events::DragDrop`
## Testing
- Not being used in tests or examples, so I just compiled.
---
</details>
## Migration Guide
- Rename `Drop` to `DragDrop`
- `bevy::picking::events::Drop` is now `bevy::picking::events::DragDrop`
# Objective
This is a value that is and will be used as a domain of curves pretty
often. By adding it as a dedicated constant we can get rid of some
`unwraps` and function calls.
## Solution
added `Interval::UNIT`
## Testing
I replaced all occurrences of `interval(0.0, 1.0).unwrap()` with the new
`Interval::UNIT` constant in tests and doc tests.
# Objective
- I needed to run a system whenever a specific condition became true
after being previously false.
- Other users might also need to run a system when a condition changes,
regardless of if it became true or false.
## Solution
- This adds two systems to common_conditions:
- `condition_changed` that changes whenever the inner condition changes
- `condition_became_true` that returns true whenever the inner condition
becomes true after previously being false
## Testing
- I added a doctest for each function
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Allow not only inserting `Data` into `EmbeddedAssetRegistry` and `Dir`
in turn but now also removing it again.
- This way when used to embed asset data from *somewhere* but not load
it using the conventional means via `AssetServer` (which I observed
takes ownership of the `Data`) the `Data` does not need to stay in
memory of the `EmbeddedAssetRegistry` throughout the lifetime of the
application.
## Solution
- added the `remove_asset` functions in `EmbeddedAssetRegistry` and
`Dir`
## Testing
- added a module unittest
- does this require changes if build with feature `embedded_watcher`?
# Objective
Fixes#14883
## Solution
Pretty simple update to `EntityCommands` methods to consume `self` and
return it rather than taking `&mut self`. The things probably worth
noting:
* I added `#[allow(clippy::should_implement_trait)]` to the `add` method
because it causes a linting conflict with `std::ops::Add`.
* `despawn` and `log_components` now return `Self`. I'm not sure if
that's exactly the desired behavior so I'm happy to adjust if that seems
wrong.
## Testing
Tested with `cargo run -p ci`. I think that should be sufficient to call
things good.
## Migration Guide
The most likely migration needed is changing code from this:
```
let mut entity = commands.get_or_spawn(entity);
if depth_prepass {
entity.insert(DepthPrepass);
}
if normal_prepass {
entity.insert(NormalPrepass);
}
if motion_vector_prepass {
entity.insert(MotionVectorPrepass);
}
if deferred_prepass {
entity.insert(DeferredPrepass);
}
```
to this:
```
let mut entity = commands.get_or_spawn(entity);
if depth_prepass {
entity = entity.insert(DepthPrepass);
}
if normal_prepass {
entity = entity.insert(NormalPrepass);
}
if motion_vector_prepass {
entity = entity.insert(MotionVectorPrepass);
}
if deferred_prepass {
entity.insert(DeferredPrepass);
}
```
as can be seen in several of the example code updates here. There will
probably also be instances where mutable `EntityCommands` vars no longer
need to be mutable.
# Objective
Based on the discussion in #14864, I wanted to experiment with the core
`GenericTypeCell` type, whose `get_or_insert` method accounted for 2% of
the final binary size of the `3d_scene` example. The reason for this
large percentage is likely because the type is fundamental to the rest
of Bevy while having 3 generic parameters (the type stored `T`, the type
to retrieve `G`, and the function used to insert a new value `F`).
- Acts on #14864
## Solution
- Split `get_or_insert` into smaller functions with minimised
parameterisation. These new functions are private as to preserve the
public facing API, but could be exposed if desired.
## Testing
- Ran CI locally.
- Used `cargo bloat --release --example 3d_scene -n 100000
--message-format json > out.json` and @cart's [bloat
analyzer](https://gist.github.com/cart/722756ba3da0e983d207633e0a48a8ab)
to measure a 428KiB reduction in binary size when compiling on Windows
10.
- ~I have _not_ benchmarked to determine if this improves/hurts
performance.~ See
[below](https://github.com/bevyengine/bevy/pull/14865#issuecomment-2306083606).
## Notes
In my opinion this seems like a good test-case for the concept of
debloating generics within the Bevy codebase. I believe the performance
impact here is negligible in either direction (at runtime and compile
time), but the binary reduction is measurable and quite significant for
a relatively minor change in code.
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
Citing @mweatherley
> As mentioned before, a multi-sampling function in the API which takes
an iterator is probably something we want (e.g. `sample_iter(iter: impl
IntoIterator<Item = f32>) -> impl IntoIterator<Item = T> { //... }`, but
there are some design choices to be made on the details (e.g. does this
filter out points that aren't in the domain? does it do sorting? etc.)
## Solution
I think the most flexible solution for end users is to expose all the
`sample_...` functions with an `iter` equivalent, so we'll have
- `sample_iter`
- `sample_iter_unchecked`
- `sample_iter_clamped`
Answering some questions from the original idea:
> does this filter out points that aren't in the domain?
With the methods the user has the choice to just sample or if they want
to filter out invalid types us `sample_iter` and then apply `filter_map`
to the iterator returned themselves.
> does it do sorting?
I think it's the same thing. If the user wants it, they need to do it
themselves by either collecting and sorting a `Vec` or using
`itertools`. I think there is a legit use case for "please sample me
this collection of points that are unordered" and we would destroy it if
we take away to much agency from users by sorting for them
## Testing
- Added a test which covers all three methods
# Objective
Add `bevy_picking` sprite backend as part of the `bevy_mod_picking`
upstreamening (#12365).
## Solution
More or less a copy/paste from `bevy_mod_picking`, with the changes
[here](https://github.com/aevyrie/bevy_mod_picking/pull/354). I'm
putting that link here since those changes haven't yet made it through
review, so should probably be reviewed on their own.
## Testing
I couldn't find any sprite-backend-specific tests in `bevy_mod_picking`
and unfortunately I'm not familiar enough with Bevy's testing patterns
to write tests for code that relies on windowing and input. I'm willing
to break the pointer hit system into testable blocks and add some more
modular tests if that's deemed important enough to block, otherwise I
can open an issue for adding tests as follow-up.
## Follow-up work
- More docs/tests
- Ignore pick events on transparent sprite pixels with potential opt-out
---------
Co-authored-by: Aevyrie <aevyrie@gmail.com>
# Objective
`arc_2d` wasn't actually doing what the docs were saying. The arc wasn't
offset by what was previously `direction_angle` but by `direction_angle
- arc_angle / 2.0`. This meant that the arcs center was laying on the
`Vec2::Y` axis and then it was offset. This was probably done to fit the
behavior of the `Arc2D` primitive. I would argue that this isn't
desirable for the plain `arc_2d` gizmo method since
- a) the docs get longer to explain the weird centering
- b) the mental model the user has to know gets bigger with more
implicit assumptions
given the code
```rust
my_gizmos.arc_2d(Vec2::ZERO, 0.0, FRAC_PI_2, 75.0, ORANGE_RED);
```
we get
![image](https://github.com/user-attachments/assets/84894c6d-42e4-451b-b3e2-811266486ede)
where after the fix with
```rust
my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 75.0, ORANGE_RED);
```
we get
![image](https://github.com/user-attachments/assets/16b0aba0-f7b5-4600-ac49-a22be0315c40)
To get the same result with the previous implementation you would have
to randomly add `arc_angle / 2.0` to the `direction_angle`.
```rust
my_gizmos.arc_2d(Vec2::ZERO, FRAC_PI_4, FRAC_PI_2, 75.0, ORANGE_RED);
```
This makes constructing similar helping functions as they already exist
in 3D like
- `long_arc_2d_between`
- `short_arc_2d_between`
much harder.
## Solution
- Make the arc really start at `Vec2::Y * radius` in counter-clockwise
direction + offset by an angle as the docs state it
- Use `Isometry2d` instead of `position : Vec2` and `direction_angle :
f32` to reduce the chance of messing up rotation/translation
- Adjust the docs for the changes above
- Adjust the gizmo rendering of some primitives
## Testing
- check `2d_gizmos.rs` and `render_primitives.rs` examples
## Migration Guide
- users have to adjust their usages of `arc_2d`:
- before:
```rust
arc_2d(
pos,
angle,
arc_angle,
radius,
color
)
```
- after:
```rust
arc_2d(
// this `+ arc_angle * 0.5` quirk is only if you want to preserve the
previous behavior
// with the new API.
// feel free to try to fix this though since your current calls to this
function most likely
// involve some computations to counter-act that quirk in the first
place
Isometry2d::new(pos, Rot2::radians(angle + arc_angle * 0.5),
arc_angle,
radius,
color
)
```
# Objective
- Faster meshlet rasterization path for small triangles
- Avoid having to allocate and write out a triangle buffer
- Refactor gpu_scene.rs
## Solution
- Replace the 32bit visbuffer texture with a 64bit visbuffer buffer,
where the left 32 bits encode depth, and the right 32 bits encode the
existing cluster + triangle IDs. Can't use 64bit textures, wgpu/naga
doesn't support atomic ops on textures yet.
- Instead of writing out a buffer of packed cluster + triangle IDs (per
triangle) to raster, the culling pass now writes out a buffer of just
cluster IDs (per cluster, so less memory allocated, cheaper to write
out).
- Clusters for software raster are allocated from the left side
- Clusters for hardware raster are allocated in the same buffer, from
the right side
- The buffer size is fixed at MeshletPlugin build time, and should be
set to a reasonable value for your scene (no warning on overflow, and no
good way to determine what value you need outside of renderdoc - I plan
to fix this in a future PR adding a meshlet stats overlay)
- Currently I don't have a heuristic for software vs hardware raster
selection for each cluster. The existing code is just a placeholder. I
need to profile on a release scene and come up with a heuristic,
probably in a future PR.
- The culling shader is getting pretty hard to follow at this point, but
I don't want to spend time improving it as the entire shader/pass is
getting rewritten/replaced in the near future.
- Software raster is a compute workgroup per-cluster. Each workgroup
loads and transforms the <=64 vertices of the cluster, and then
rasterizes the <=64 triangles of the cluster.
- Two variants are implemented: Scanline for clusters with any larger
triangles (still smaller than hardware is good at), and brute-force for
very very tiny triangles
- Once the shader determines that a pixel should be filled in, it does
an atomicMax() on the visbuffer to store the results, copying how Nanite
works
- On devices with a low max workgroups per dispatch limit, an extra
compute pass is inserted before software raster to convert from a 1d to
2d dispatch (I don't think 3d would ever be necessary).
- I haven't implemented the top-left rule or subpixel precision yet, I'm
leaving that for a future PR since I get usable results without it for
now
- Resources used:
https://kristoffer-dyrkorn.github.io/triangle-rasterizer and chapters
6-8 of
https://fgiesen.wordpress.com/2013/02/17/optimizing-sw-occlusion-culling-index
- Hardware raster now spawns 64*3 vertex invocations per meshlet,
instead of the actual meshlet vertex count. Extra invocations just
early-exit.
- While this is slower than the existing system, hardware draws should
be rare now that software raster is usable, and it saves a ton of memory
using the unified cluster ID buffer. This would be fixed if wgpu had
support for mesh shaders.
- Instead of writing to a color+depth attachment, the hardware raster
pass also does the same atomic visbuffer writes that software raster
uses.
- We have to bind a dummy render target anyways, as wgpu doesn't
currently support render passes without any attachments
- Material IDs are no longer written out during the main rasterization
passes.
- If we had async compute queues, we could overlap the software and
hardware raster passes.
- New material and depth resolve passes run at the end of the visbuffer
node, and write out view depth and material ID depth textures
### Misc changes
- Fixed cluster culling importing, but never actually using the previous
view uniforms when doing occlusion culling
- Fixed incorrectly adding the LOD error twice when building the meshlet
mesh
- Splitup gpu_scene module into meshlet_mesh_manager, instance_manager,
and resource_manager
- resource_manager is still too complex and inefficient (extract and
prepare are way too expensive). I plan on improving this in a future PR,
but for now ResourceManager is mostly a 1:1 port of the leftover
MeshletGpuScene bits.
- Material draw passes have been renamed to the more accurate material
shade pass, as well as some other misc renaming (in the future, these
will be compute shaders even, and not actual draw calls)
---
## Migration Guide
- TBD (ask me at the end of the release for meshlet changes as a whole)
---------
Co-authored-by: vero <email@atlasdostal.com>
# Objective
When using instancing, 2 `VertexBufferLayout`s are needed, one for
per-vertex and one for per-instance data. Shader locations of all
attributes must not overlap, so one of the layouts needs to start its
locations at an offset. However,
`VertexBufferLayout::from_vertex_formats` will always start locations at
0, requiring manual adjustment, which is currently pretty verbose.
## Solution
Add `VertexBufferLayout::offset_locations`, which adds an offset to all
attribute locations.
Code using this method looks like this:
```rust
VertexState {
shader: BACKBUFFER_SHADER_HANDLE.typed(),
shader_defs: Vec::new(),
entry_point: "vertex".into(),
buffers: vec![
VertexBufferLayout::from_vertex_formats(
VertexStepMode::Vertex,
[VertexFormat::Float32x2],
),
VertexBufferLayout::from_vertex_formats(
VertexStepMode::Instance,
[VertexFormat::Float32x2, VertexFormat::Float32x3],
)
.offset_locations(1),
],
}
```
Alternative solutions include:
- Pass the starting location to `from_vertex_formats` – this is a bit
simpler than my solution here, but most calls don't need an offset, so
they'd always pass 0 there.
- Do nothing and make the user hand-write this.
---
## Changelog
- Add `VertexBufferLayout::offset_locations` to simplify buffer layout
construction when using instancing.
---------
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Adding more features to `AsBindGroup` proc macro means making the trait
arguments uglier. Downstream implementors of the trait without the proc
macro might want to do different things than our default arguments.
## Solution
Make `AsBindGroup` take an associated `Param` type.
## Migration Guide
`AsBindGroup` now allows the user to specify a `SystemParam` to be used
for creating bind groups.
# Objective
Closes#7622.
I was working on adding support for reflecting generic functions and
found that I wanted to use an argument's `TypeId` for hashing and
comparison, but its `TypePath` for debugging and error messaging.
While I could just keep them separate, place them in a tuple or a local
struct or something, I think I see an opportunity to make a dedicate
type for this.
Additionally, we can use this type to clean up some duplication amongst
the type info structs in a manner similar to #7622.
## Solution
Added the `Type` type. This should be seen as the most basic
representation of a type apart from `TypeId`. It stores both the
`TypeId` of the type as well as its `TypePathTable`.
The `Hash` and `PartialEq` implementations rely on the `TypeId`, while
the `Debug` implementation relies on the `TypePath`.
This makes it especially useful as a key in a `HashMap` since we get the
speed of the `TypeId` hashing/comparisons with the readability of
`TypePath`.
With this type, we're able to reduce the duplication across the type
info structs by removing individual fields for `TypeId` and
`TypePathTable`, replacing them with a single `Type` field. Similarly,
we can remove many duplicate methods and replace it with a macro that
delegates to the stored `Type`.
### Caveats
It should be noted that this type is currently 3x larger than `TypeId`.
On my machine, it's 48 bytes compared to `TypeId`'s 16. While this
doesn't matter for `TypeInfo` since it would contain that data
regardless, it is something to keep in mind when using elsewhere.
## Testing
All tests should pass as normal:
```
cargo test --package bevy_reflect
```
---
## Showcase
`bevy_reflect` now exports a `Type` struct. This type contains both the
`TypeId` and the `TypePathTable` of the given type, allowing it to be
used like `TypeId` but have the debuggability of `TypePath`.
```rust
// We can create this for any type implementing `TypePath`:
let ty = Type::of::<String>();
// It has `Hash` and `Eq` impls powered by `TypeId`, making it useful for maps:
let mut map = HashMap::<Type, i32>::new();
map.insert(ty, 25);
// And it has a human-readable `Debug` representation:
let debug = format!("{:?}", map);
assert_eq!(debug, "{alloc::string::String: 25}");
```
## Migration Guide
Certain type info structs now only return their item types as `Type`
instead of exposing direct methods on them.
The following methods have been removed:
- `ArrayInfo::item_type_path_table`
- `ArrayInfo::item_type_id`
- `ArrayInfo::item_is`
- `ListInfo::item_type_path_table`
- `ListInfo::item_type_id`
- `ListInfo::item_is`
- `SetInfo::value_type_path_table`
- `SetInfo::value_type_id`
- `SetInfo::value_is`
- `MapInfo::key_type_path_table`
- `MapInfo::key_type_id`
- `MapInfo::key_is`
- `MapInfo::value_type_path_table`
- `MapInfo::value_type_id`
- `MapInfo::value_is`
Instead, access the `Type` directly using one of the new methods:
- `ArrayInfo::item_ty`
- `ListInfo::item_ty`
- `SetInfo::value_ty`
- `MapInfo::key_ty`
- `MapInfo::value_ty`
For example:
```rust
// BEFORE
let type_id = array_info.item_type_id();
// AFTER
let type_id = array_info.item_ty().id();
```
# Objective
I tried writing something like this in my project
```rust
.observe(|e: Trigger<OnAdd, Skeleton>| {
panic!("Skeletoned! {e:?}");
});
```
and it didn't compile.
Having `Debug` trait defined on `Trigger` event will ease debugging the
observers a little bit.
## Solution
Add a bespoke `Debug` implementation when both the bundle and the event
have `Debug` implemented for them.
## Testing
I've added `println!("{trigger:#?}");` to the [observers
example](938d810766/examples/ecs/observers.rs (L124))
and it compiled!
Caveats with this PR are:
- removing this implementation if for any reason we will need it, will
be a breaking change
- the implementation is manually generated, which adds potential toil
when changing the `Trigger` structure
## Showcase
Log output:
```rust
on_add_mine: Trigger {
event: OnAdd,
propagate: false,
trigger: ObserverTrigger {
observer: 2v1#4294967298,
event_type: ComponentId(
0,
),
entity: 454v1#4294967750,
},
_marker: PhantomData<observers::Mine>,
}
```
Thank you for maintaining this engine! 🧡
# Objective
- Gizmo rendering on WebGPU has been fixed by #14653, but gizmo joints
still cause error
(https://github.com/bevyengine/bevy/issues/14696#issuecomment-2283689669)
when enabled.
## Solution
- Applies the same fix as #14653 to Gizmo joints.
I'm noob and just copied their solution, please correct me if I did
something wrong.
## Testing
- Tested 2d-gizmos and 3d-gizmos examples in WebGPU on Chrome. No
rendering errors, and the gizmo joints are apparently rendered ok.
# Objective
Support building systems with parameters whose types can be determined
at runtime.
## Solution
Create a `DynSystemParam` type that can be built using a
`SystemParamBuilder` of any type and then downcast to the appropriate
type dynamically.
## Example
```rust
let system = (
DynParamBuilder::new(LocalBuilder(3_usize)),
DynParamBuilder:🆕:<Query<()>>(QueryParamBuilder::new(|builder| {
builder.with::<A>();
})),
DynParamBuilder:🆕:<&Entities>(ParamBuilder),
)
.build_state(&mut world)
.build_system(
|mut p0: DynSystemParam, mut p1: DynSystemParam, mut p2: DynSystemParam| {
let local = p0.downcast_mut::<Local<usize>>().unwrap();
let query_count = p1.downcast_mut::<Query<()>>().unwrap();
let entities = p2.downcast_mut::<&Entities>().unwrap();
},
);
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Periwink <charlesbour@gmail.com>
# Objective
- Remove the `wgpu_trace` feature while still making it easy/possible to
record wgpu traces for debugging.
- Close#14725.
- Get a taste of the bevy codebase. :P
## Solution
This PR performs the above objective by removing the `wgpu_trace`
feature from all `Cargo.toml` files.
However, wgpu traces are still useful for debugging - but to record
them, you need to pass in a directory path to store the traces in. To
avoid forcing users into manually creating the renderer,
`bevy_render::settings::WgpuSettings` now has a `trace_path` field, so
that all of Bevy's automatic initialization can happen while still
allowing for tracing.
## Testing
- Did you test these changes? If so, how?
- I have tested these changes, but only via running `cargo run -p ci`. I
am hoping the Github Actions workflows will catch anything I missed.
- Are there any parts that need more testing?
- I do not believe so.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If you want to test these changes, I have updated the debugging guide
(`docs/debugging.md`) section on WGPU Tracing.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- I ran the above command on a Windows 10 64-bit (x64) machine, using
the `stable-x86_64-pc-windows-msvc` toolchain. I do not have anything
set up for other platforms or targets (though I can't imagine this needs
testing on other platforms).
---
## Migration Guide
1. The `bevy/wgpu_trace`, `bevy_render/wgpu_trace`, and
`bevy_internal/wgpu_trace` features no longer exist. Remove them from
your `Cargo.toml`, CI, tooling, and what-not.
2. Follow the instructions in the updated `docs/debugging.md` file in
the repository, under the WGPU Tracing section.
Because of the changes made, you can now generate traces to any path,
rather than the hardcoded `%WorkspaceRoot%/wgpu_trace` (where
`%WorkspaceRoot%` is... the root of your crate's workspace) folder.
(If WGPU hasn't restored tracing functionality...) Do note that WGPU has
not yet restored tracing functionality. However, once it does, the above
should be sufficient to generate new traces.
---------
Co-authored-by: TrialDragon <31419708+TrialDragon@users.noreply.github.com>
# Objective
Add a convenience constructor to make simple animation graphs easier to
build.
I've had some notes about attempting this since #11989 that I just
remembered after seeing #14852.
This partially addresses #14852, but I don't really know animation well
enough to write all of the documentation it's asking for.
## Solution
Add `AnimationGraph::from_clips` and use it to simplify `animated_fox`.
Do some other little bits of incidental cleanup and documentation .
## Testing
I ran `cargo run --example animated_fox`.
# Objective
- Fixes#14658.
## Solution
- Added `on_unimplemented` Diagnostic for `IntoObserverSystem` calling
out argument ordering in a `note`
- Added an example to the documentation on `App::observe` to provide
some explanation to users.
## Testing
- Ran CI locally
- Deliberately introduced a parameter order error in the
`ecs/observers.rs` example as a test.
---
## Showcase
<details>
<summary>Error Before</summary>
```
error[E0277]: the trait bound `{closure@examples/ecs/observers.rs:19:13: 22:37}: IntoObserverSystem<_, _, _>` is not satisfied
--> examples/ecs/observers.rs:19:13
|
18 | .observe(
| ------- required by a bound introduced by this call
19 | / |mines: Query<&Mine>,
20 | | trigger: Trigger<ExplodeMines>,
21 | | index: Res<SpatialIndex>,
22 | | mut commands: Commands| {
... |
34 | | }
35 | | },
| |_____________^ the trait `bevy::prelude::IntoSystem<bevy::prelude::Trigger<'static, _, _>, (), _>` is not implemented for closure `{closure@examples/ecs/observers.rs:19:13: 22:37}`, which is required by `{closure@examples/ecs/observers.rs:19:13: 22:37}: IntoObserverSystem<_, _, _>`
|
= note: required for `{closure@examples/ecs/observers.rs:19:13: 22:37}` to implement `IntoObserverSystem<_, _, _>`
note: required by a bound in `bevy::prelude::App::observe`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:995:24
|
993 | pub fn observe<E: Event, B: Bundle, M>(
| ------- required by a bound in this associated function
994 | &mut self,
995 | observer: impl IntoObserverSystem<E, B, M>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::observe`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `bevy` (example "observers") due to 1 previous error
```
</details>
<details>
<summary>Error After</summary>
```
error[E0277]: `{closure@examples/ecs/observers.rs:19:13: 22:37}` cannot become an `ObserverSystem`
--> examples/ecs/observers.rs:19:13
|
18 | .observe(
| ------- required by a bound introduced by this call
19 | / |mines: Query<&Mine>,
20 | | trigger: Trigger<ExplodeMines>,
21 | | index: Res<SpatialIndex>,
22 | | mut commands: Commands| {
... |
34 | | }
35 | | },
| |_____________^ the trait `IntoObserverSystem` is not implemented
|
= help: the trait `bevy::prelude::IntoSystem<bevy::prelude::Trigger<'static, _, _>, (), _>` is not implemented for closure `{closure@examples/ecs/observers.rs:19:13: 22:37}`, which is required by `{closure@examples/ecs/observers.rs:19:13: 22:37}: IntoObserverSystem<_, _, _>`
= note: for function `ObserverSystem`s, ensure the first argument is a `Trigger<T>` and any subsequent ones are `SystemParam`
= note: required for `{closure@examples/ecs/observers.rs:19:13: 22:37}` to implement `IntoObserverSystem<_, _, _>`
note: required by a bound in `bevy::prelude::App::observe`
--> C:\Users\Zac\Documents\GitHub\bevy\crates\bevy_app\src\app.rs:1025:24
|
1023 | pub fn observe<E: Event, B: Bundle, M>(
| ------- required by a bound in this associated function
1024 | &mut self,
1025 | observer: impl IntoObserverSystem<E, B, M>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `App::observe`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `bevy` (example "observers") due to 1 previous error
```
</details>
# Objective
Rewrite screenshotting to be able to accept any `RenderTarget`.
Closes#12478
## Solution
Previously, screenshotting relied on setting a variety of state on the
requested window. When extracted, the window's `swap_chain_texture_view`
property would be swapped out with a texture_view created that frame for
the screenshot pipeline to write back to the cpu.
Besides being tightly coupled to window in a way that prevented
screenshotting other render targets, this approach had the drawback of
relying on the implicit state of `swap_chain_texture_view` being
returned from a `NormalizedRenderTarget` when view targets were
prepared. Because property is set every frame for windows, that wasn't a
problem, but poses a problem for render target images. Namely, to do the
equivalent trick, we'd have to replace the `GpuImage`'s texture view,
and somehow restore it later.
As such, this PR creates a new `prepare_view_textures` system which runs
before `prepare_view_targets` that allows a new `prepare_screenshots`
system to be sandwiched between and overwrite the render targets texture
view if a screenshot has been requested that frame for the given target.
Additionally, screenshotting itself has been changed to use a component
+ observer pattern. We now spawn a `Screenshot` component into the
world, whose lifetime is tracked with a series of marker components.
When the screenshot is read back to the CPU, we send the image over a
channel back to the main world where an observer fires on the screenshot
entity before being despawned the next frame. This allows the user to
access resources in their save callback that might be useful (e.g.
uploading the screenshot over the network, etc.).
## Testing
![image](https://github.com/user-attachments/assets/48f19aed-d9e1-4058-bb17-82b37f992b7b)
TODO:
- [x] Web
- [ ] Manual texture view
---
## Showcase
render to texture example:
<img
src="https://github.com/user-attachments/assets/612ac47b-8a24-4287-a745-3051837963b0"
width=200/>
web saving still works:
<img
src="https://github.com/user-attachments/assets/e2a15b17-1ff5-4006-ab2a-e5cc74888b9c"
width=200/>
## Migration Guide
`ScreenshotManager` has been removed. To take a screenshot, spawn a
`Screenshot` entity with the specified render target and provide an
observer targeting the `ScreenshotCaptured` event. See the
`window/screenshot` example to see an example.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
# Objective
`ParamSetBuilder` is supposed to be used as a tuple constructor, but the
field was not marked `pub` so it's not actually usable outside of its
module.
## Solution
Mark the field `pub`.
Realize one advantage of doc tests over unit tests is that they test the
public API.
Add a doc test example that uses the field so that this would have been
caught.
# Objective
There is a tiny seam at the top of the annulus caused by normal
floating-point error in calculating the coordinates. When generating the
last pair of triangles, given `n == i` then `(TAU / n) * i` does not
equal `TAU` exactly.
Fixes https://github.com/komadori/bevy_mod_outline/issues/42
## Solution
This can be fixed by changing the calculation so that `(TAU / n) * (i %
n) == 0.0`, which is equivalent for trigonometric purposes.
## Testing
Added the unit test
`bevy_render::mesh::primitives::dim2::tests::test_annulus`.
Fixes#14825
Edit: After feedback, these are the updated methods:
- `toggle_inherited_visible(&mut self)`
- Toggles between `Visibility::Inherited` and `Visibility::Visible`. If
the value is `Visibility::Hidden`, it remains unaffected.
- `toggle_inherited_hidden(&mut self)`
- Toggles between `Visibility::Inherited` and `Visibility::Hidden`. If
the value is `Visibility::Visible`, it remains unaffected.
- `toggle_visible_hidden(&mut self)`
- Toggles between `Visibility::Visible` and `Visibility::Hidden`. If the
value is `Visibility::Inherited`, it remains unaffected.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
- There is a flaw in the implementation of `FogVolume`'s
`density_texture_offset` from #14868. Because of the way I am wrapping
the UVW coordinates in the volumetric fog shader, a seam is visible when
the 3d texture is wrapping around from one side to the other:
![density_texture_offset_seam](https://github.com/user-attachments/assets/89527ef2-5e1b-4b90-8e73-7a3e607697d4)
## Solution
- This PR fixes the issue by removing the wrapping from the shader and
instead leaving it to the user to configure the 3d noise texture to use
`ImageAddressMode::Repeat` if they want it to repeat. Using
`ImageAddressMode::Repeat` is the proper solution to avoid the obvious
seam:
![density_texture_seam_fixed](https://github.com/user-attachments/assets/06e871a6-2db1-4501-b425-4141605f9b26)
- The sampler cannot be implicitly configured to use
`ImageAddressMode::Repeat` because that's not always desirable. For
example, the `fog_volumes` example wouldn't work properly because the
texture from the edges of the volume would overflow to the other sides,
which would be bad in this instance (but it's good in the case of the
`scrolling_fog` example). So leaving it to the user to decide on their
own whether they want the density texture to repeat seems to be the best
solution.
## Testing
- The `scrolling_fog` example still looks the same, it was just changed
to explicitly declare that the density texture should be repeating when
loading the asset. The `fog_volumes` example is unaffected.
<details>
<summary>Minimal reproduction example on current main</summary>
<pre>
use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle,
TemporalAntiAliasPlugin};
use bevy::pbr::{FogVolume, VolumetricFogSettings, VolumetricLight};
use bevy::prelude::*;<br>
fn main() {
App::new()
.add_plugins((DefaultPlugins, TemporalAntiAliasPlugin))
.add_systems(Startup, setup)
.run();
}<br>
fn setup(mut commands: Commands, assets: Res<AssetServer>) {
commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(3.5, -1.0, 0.4)
.looking_at(Vec3::new(0.0, 0.0, 0.4), Vec3::Y),
msaa: Msaa::Off,
..default()
},
TemporalAntiAliasBundle::default(),
VolumetricFogSettings {
ambient_intensity: 0.0,
jitter: 0.5,
..default()
},
));<br>
commands.spawn((
DirectionalLightBundle {
transform: Transform::from_xyz(-6.0, 5.0, -9.0)
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
directional_light: DirectionalLight {
illuminance: 32_000.0,
shadows_enabled: true,
..default()
},
..default()
},
VolumetricLight,
));<br>
commands.spawn((
SpatialBundle {
visibility: Visibility::Visible,
transform: Transform::from_xyz(0.0, 0.0,
0.0).with_scale(Vec3::splat(3.0)),
..default()
},
FogVolume {
density_texture: Some(assets.load("volumes/fog_noise.ktx2")),
density_texture_offset: Vec3::new(0.0, 0.0, 0.4),
scattering: 1.0,
..default()
},
));
}
</pre>
</details>
# Objective
- Fixes#14873, see that issue for a whole lot of context
## Solution
- Add a blessed system set for this stuff. See [this Discord
discussion](https://discord.com/channels/691052431525675048/749335865876021248/1276262931327094908).
Note that the gizmo systems,
[LWIM](https://github.com/Leafwing-Studios/leafwing-input-manager/pull/522/files#diff-9b59ee4899ad0a5d008889ea89a124a7291316532e42f9f3d6ae842b906fb095R154)
and now a new plugin I'm working on are all already ordering against
`run_fixed_main_schedule`, so having a dedicated system set should be
more robust and hopefully also more discoverable.
---
## ~~Showcase~~
~~I can add a little video of a smooth camera later if this gets merged
:)~~
Apparently a release note is not needed, so I'll leave it out. See the
changes in the fixed timestep example for usage showcase and the video
in #14873 for a more or less accurate video of the effect (it does not
use the same solution though, so it is not quite the same)
## Migration Guide
[run_fixed_main_schedule](https://docs.rs/bevy/latest/bevy/time/fn.run_fixed_main_schedule.html)
is no longer public. If you used to order against it, use the new
dedicated `RunFixedMainLoopSystem` system set instead. You can replace
your usage of `run_fixed_main_schedule` one for one by
`RunFixedMainLoopSystem::FixedMainLoop`, but it is now more idiomatic to
place your systems in either
`RunFixedMainLoopSystem::BeforeFixedMainLoop` or
`RunFixedMainLoopSystem::AfterFixedMainLoop`
Old:
```rust
app.add_systems(
RunFixedMainLoop,
some_system.before(run_fixed_main_schedule)
);
```
New:
```rust
app.add_systems(
RunFixedMainLoop,
some_system.in_set(RunFixedMainLoopSystem::BeforeFixedMainLoop)
);
```
---------
Co-authored-by: Tau Gärtli <git@tau.garden>
# Objective
When trying to test a gizmos change I ran `cargo test -p bevy_gizmos`
and the output had a lot of noise from warnings and failed doc errors.
This was because I didn't have all of the features enabled.
## Solution
I admit this might be pedantic, and am happy if the concensus is to
reject it. Although it does reduce the lines of code, testing noise, and
the amount of code compiled. I don't think it affects the complexity of
public code, and it doesn't change much to the complexity of internal
code.
I've removed un-needed `bevy_render` imports in all of the gizmos docs
examples, there's probably other unnecessary ones there too, but I
haven't looked exhaustively. It isn't needed for those docs, and isn't
available except in a subset of `cfg` combinations.
I've also made several of the `use` statements slightly more specific. I
shouldn't have changed the public interfaces, except that
`GizmoMeshConfig` requires either `bevy_sprite` or `bevy_pbr`, as it
does nothing without them.
I've also avoided adding some systems and plugins in situations where
they can't work. An example of this is where the `light` module depends
on `all(feature = "bevy_pbr", feature = "bevy_render")`, but it has
`use` statements that only require `bevy_render`.
## Testing
During development I ran:
```
cargo check -p bevy_gizmos && cargo check -p bevy_gizmos --features=bevy_pbr && cargo check -p bevy_gizmos --features=bevy_sprite && cargo check -p bevy_gizmos --features=bevy_render
```
Afterwards I ran this just to be sure:
```
cargo check && cargo check --features=bevy_pbr && cargo check --features=bevy_sprite && cargo check --features=bevy_render
```
Finally I ran:
```
cargo test -p bevy_gizmos && cargo test -p bevy_gizmos --features=bevy_pbr && test check -p bevy_gizmos --features=bevy_sprite && cargo test -p bevy_gizmos --features=bevy_render
```
## Migration Guide
There shouldn't be any reason to migrate, although if for some reason
you use `GizmoMeshConfig` and `bevy_render` but not `bevy_pbr` or
`bevy_sprite` (such that it does nothing), then you will get an error
that it no longer exists.
# Objective
It looks like `Gizmos::grid*` was missed in the colour migration.
## Solution
This updates the `grid` methods and implementation to use `Color`
instead of `LinearRgba`.
It looks like `ExtractedPointLight` and `ExtractedDirectionalLight` also
use `LinearRgba`, although I think in extracted structures it's probably
fine to make more assumptions about what you want?
## Testing
I ran `cargo test --all -- bevy_gizmos` and it passed.
## Migration Guide
This shouldn't be adding anything that isn't already in a migration
guide? I assume as it uses `impl Into<...>` in the public interfaces
that any users of these APIs shouldn't have to make any code changes.
# Objective
- Fixes#14844
## Solution
- implement reflect using the `impl_reflect_value` macro
## Testing
- I wrote a test locally to understand and learn how reflection worked
on a basic level and to confirm that yes indeed the bound struct could
use the reflection traits that have been implemented for it.
note: I did remove a line that asked for bound to not have reflect
implemented in a test, since that's the point of this PR and the test
worked without the line so I am not sure what that was about, not sure
if that uncovers a deeper issue or not.
# Objective
- The goal of this PR is to make it possible to move the density texture
of a `FogVolume` over time in order to create dynamic effects like fog
moving in the wind.
- You could theoretically move the `FogVolume` itself, but this is not
ideal, because the `FogVolume` AABB would eventually leave the area. If
you want an area to remain foggy while also creating the impression that
the fog is moving in the wind, a scrolling density texture is a better
solution.
## Solution
- The PR adds a `density_texture_offset` field to the `FogVolume`
component. This offset is in the UVW coordinates of the density texture,
meaning that a value of `(0.5, 0.0, 0.0)` moves the 3d texture by half
along the x-axis.
- Values above 1.0 are wrapped, a 1.5 offset is the same as a 0.5
offset. This makes it so that the density texture wraps around on the
other side, meaning that a repeating 3d noise texture can seamlessly
scroll forever. It also makes it easy to move the density texture over
time by simply increasing the offset every frame.
## Testing
- A `scrolling_fog` example has been added to demonstrate the feature.
It uses the offset to scroll a repeating 3d noise density texture to
create the impression of fog moving in the wind.
- The camera is looking at a pillar with the sun peaking behind it. This
highlights the effect the changing density has on the volumetric
lighting interactions.
- Temporal anti-aliasing combined with the `jitter` option of
`VolumetricFogSettings` is used to improve the quality of the effect.
---
## Showcase
https://github.com/user-attachments/assets/3aa50ebd-771c-4c99-ab5d-255c0c3be1a8
Closes#14836.
`filter_map_unchanged` optionally maps to an inner value by applying a
function to the contained reference. This is useful in a situation where
you need to convert a `Mut<T>` to a `Mut<U>`, but only if `T` contains
`U`.
---------
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
# Objective
- Fixes#14796
## Solution
- Copy docs for wrapper methods, make sure they are consistent with the
original docs except for the section on precision.
# Objective
`RenderLayers` was marketed as being unlimited in the Bevy 0.14 release
notes, but the most obvious constructor doesn't actually support
unlimited layers.
We should explicitly document this.
## Solution
Add some docs mentioning the limit and pointing the user to `with` or
`from_layers` if they need an arbitrary number of layers.
# Objective
Fixes#14782
## Solution
Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?
Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.
## Testing
`cargo clippy` and `cargo run -p ci` are happy.
# Objective
add a quick shorthand for creating a sprite with an custom size. This is
often desired when working with custom units or scaled sprites and
allows for a cleaner syntax in those cases/
## Solution
Implemented a `sized` function on the Sprite struct which creates a
Sprite, sets the custom size and leaves the rest at their default values
---
## Changelog
- Added `Sprite::sized(custom_size: Vec2)`
# Objective
currently if we use an image with the wrong sampler type in a material,
wgpu panics with an invalid texture format. turn this into a warning and
fail more gracefully.
## Solution
the expected sampler type is specified in the AsBindGroup derive, so we
can just check the image sampler is what it should be.
i am not totally sure about the mapping of image sampler type to
#[sampler(type)], i assumed:
```
"filtering" => [ TextureSampleType::Float { filterable: true } ],
"non_filtering" => [
TextureSampleType::Float { filterable: false },
TextureSampleType::Sint,
TextureSampleType::Uint,
],
"comparison" => [ TextureSampleType::Depth ],
```
# Objective
- Fixes#14684
## Solution
- Added documentation to `all_tuples_with_size` based on existing
`all_tuples` documentation.
- Updated `all_tuples` documentation to match formatting of and link
back to `all_tuples_with_size`
## Testing
- Doctests ran locally.
## Notes
Formatting changes I have proposed make the documentation a little
cleaner in my opinion, but I am open to reverting them and amending
`all_tuples_with_size` to match if there are any reasonable objections.
This reverts commit e37bf18e2b, added in
#14784.
# Objective
The PR was fine, but the work was very poorly motivated and the
resulting API is not actually very nice. The actual user need is likely
better addressed by #14825.
## Solution
Revert the offending PR.
# Objective
- Fixes#10478
## Solution
Generalised `From/Into` implementations over `&str` and `Option<&str>`
for `AssetSourceId` and `AssetPath` across all lifetimes, not just
static. To maintain access to the `'static`-only specialisation, these
types (and `CowArc`) now include an `as_static` method which will apply
the specialisation.
```rust
// Snipped from `AssetApp`
fn register_asset_source(
&mut self,
id: impl Into<AssetSourceId<'static>>,
// ^^^^^^^
// | as_static is only available for 'static lifetimes
source: AssetSourceBuilder,
) -> &mut Self {
let id = id.into().as_static();
// ^^^^^^ ^^^^^^^^^
// | | Specialized (internally storing CowArc::Static)
// | Generic Into (internally storing CowArc::Borrowed)
// ...
}
```
This post-fix specialisation is available here because the actual
specialisation performed is only a marker for if/when modification or
ownership is required, making the transform a very cheap operation. For
cleanliness, I've also added `from_static`, which wraps this behaviour
in a clean shorthand designed to replace `from` calls.
---
## Changelog
- Generalised the following implementations over a generic lifetime:
- `From<&'static str> for AssetSourceId<'static>`
- `From<Option<&'static str>> for AssetSourceId<'static>`
- `From<&'static str> for AssetPath<'static>`
- `From<&'static Path> for AssetPath<'static>`
- Added `as_static` specialisation to:
- `CowArc`
- `AssetSourceId`
- `AssetPath`
- Added `from_static` specialised constructor to:
- `AssetSourceId`
- `AssetPath`
## Migration Guide
In areas where these implementations where being used, you can now add
`from_static` in order to get the original specialised implementation
which avoids creating an `Arc` internally.
```rust
// Before
let asset_path = AssetPath::from("my/path/to/an/asset.ext");
// After
let asset_path = AssetPath::from_static("my/path/to/an/asset.ext");
```
To be clear, this is only required if you wish to maintain the
performance benefit that came with the specialisation. Existing code is
_not_ broken by this change.
# Objective
One of the changes in #14704 made `DynamicFunction` effectively the same
as `DynamicClosure<'static>`. This change meant that the de facto
function type would likely be `DynamicClosure<'static>` instead of the
intended `DynamicFunction`, since the former is much more flexible.
We _could_ explore ways of making `DynamicFunction` implement `Copy`
using some unsafe code, but it likely wouldn't be worth it. And users
would likely still reach for the convenience of
`DynamicClosure<'static>` over the copy-ability of `DynamicFunction`.
The goal of this PR is to fix this confusion between the two types.
## Solution
Firstly, the `DynamicFunction` type was removed. Again, it was no
different than `DynamicClosure<'static>` so it wasn't a huge deal to
remove.
Secondly, `DynamicClosure<'env>` and `DynamicClosureMut<'env>` were
renamed to `DynamicFunction<'env>` and `DynamicFunctionMut<'env>`,
respectively.
Yes, we still ultimately kept the naming of `DynamicFunction`, but
changed its behavior to that of `DynamicClosure<'env>`. We need a term
to refer to both functions and closures, and "function" was the best
option.
[Originally](https://discord.com/channels/691052431525675048/1002362493634629796/1274091992162242710),
I was going to go with "callable" as the replacement term to encompass
both functions and closures (e.g. `DynamciCallable<'env>`). However, it
was
[suggested](https://discord.com/channels/691052431525675048/1002362493634629796/1274653581777047625)
by @SkiFire13 that the simpler "function" term could be used instead.
While "callable" is perhaps the better umbrella term—being truly
ambiguous over functions and closures— "function" is more familiar, used
more often, easier to discover, and is subjectively just
"better-sounding".
## Testing
Most changes are purely swapping type names or updating documentation,
but you can verify everything still works by running the following
command:
```
cargo test --package bevy_reflect
```
# Objective
currently if an asset loader panics, the asset is left in a perpetual
`Loading` state. this can occur with external crates (eg the image crate
panics on bad data). catch this panic and resolve the asset to `Failed`
## Solution
`AssertUnwindSafe(loader.load).catch_unwind()` and map the panic to an
`AssetLoadError`
separated out from #13170
# Objective
Delete some code that isn't actually doing anything. This was actually
discovered way back in this obsolete PR: #5513.
Also Fixes#6286
## Solution
Delete it
## Alternatives
Make `Direction` do things. But it's not totally clear to me if it's
possible to override cosmic-text's unicode bidi stuff.
## Migration Guide
`Style` no longer has a `direction` field, and `Direction` has been
deleted. They didn't do anything, so you can delete any references to
them as well.
# Objective
Fixes#14521.
## Solution
Added to methods to the VIsibility.
```rs
is_visible() -> Result<bool, String>
```
and
```rs
visbility_from_bool(bool) -> Visibility
```
## Testing
Ran
* `cargo run -p ci -- lints`
* `cargo run -p ci -- test`
* `cargo run -p ci -- compile`
it seems to be working.
However I got few error messages :`ERROR bevy_log: could not set global
logger and tracing subscriber as they are already set. Consider
disabling LogPlugin` in `cargo run -p ci -- test`, even though all test
passed. I'm not sure if that's expected behaviour
Ps. I'm new to contributing, please correct me if anything is wrong
# Objective
Some algorithms don't really work well or are not efficient in 3D space.
When we know we have points on an `InfinitePlane3d` it would be helpful
to have some utility methods to reversibly transform points on the plane
to 2D space to apply some algorithms there.
## Solution
This PR adds a few of methods to project 3D points on a plane to 2D
points and inject them back. Additionally there are some other small
common helper methods.
## Testing
- added some tests that cover the new methods
---------
Co-authored-by: Matty <weatherleymatthew@gmail.com>
# Objective
When reading the ECS code it is sometimes confusing to understand why we
have 2 accesses, one of ComponentId and one of ArchetypeComponentId
## Solution
Make the usage of these 2 accesses more explicit
---------
Co-authored-by: Pascal Hertleif <killercup@gmail.com>
# Objective
Fixes Commands not being `Send` or `Sync` anymore in 0.14 by
implementing `Send` and `Sync` for `RawCommandQueue`.
## Solution
Reference discussion in
[discord](https://discord.com/channels/691052431525675048/691052431974465548/1259464518539411570).
It seems that in https://github.com/bevyengine/bevy/pull/13249, when
adding a `RawCommandQueue` variant to the `InternalQueue`, the `Send /
Sync` traits were not implemented for it, which bubbled up all the way
to `Commands` not being `Send / Sync` anymore.
I am not very familiar with the ECS internals so I can't say whether the
`RawCommandQueue` is safe to be shared between threads, but I know for
sure that before the linked PR `Commands` were indeed `Send` and `Sync`
so that PR broke "some workflows" (mandatory
[xkcd](https://xkcd.com/1172/)).
## Testing
This PR itself includes a compile test to make sure `Commands` will
implement `Send` and `Sync`. The test itself fails without the
implementation and succeeds with it.
Furthermore, if I cherry pick the test to a previous release (i.e. 0.13)
it indeed succeeds, showing that this is a regression specific to 0.14.
---------
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
# Objective
`MeshVertexAttributeId` is currently a wrapper type around a `usize`.
Application developers are exposed to the `usize` whenever they need to
define a new custom vertex attribute, which requires them to generate a
random `usize` ID to avoid clashes with any other custom vertex
attributes in the same application. As the range of a `usize` is
platform dependent, developers on 64-bit machines may inadvertently
generate random values which will fail to compile for a 32-bit target.
The use of a `usize` here encourages non-portable behaviour and should
be replaced with a fixed width type.
## Solution
In this PR I have changed the ID type from `usize` to `u64`, but equally
a `u32` could be used at the risk of breaking some extant non-portable
programs and increasing the chance of an ID collision.
# Objective
#14098 added the `FunctionRegistry` for registering functions such that
they can be retrieved by name and used dynamically. One thing we chose
to leave out in that initial PR is support for closures.
Why support closures? Mainly, we don't want to prohibit users from
injecting environmental data into their registered functions. This
allows these functions to not leak their internals to the public API.
For example, let's say we're writing a library crate that allows users
to register callbacks for certain actions. We want to perform some
actions before invoking the user's callback so we can't just call it
directly. We need a closure for this:
```rust
registry.register("my_lib::onclick", move |event: ClickEvent| {
// ...other work...
user_onclick.call(event); // <-- Captured variable
});
```
We could have made our callback take a reference to the user's callback.
This would remove the need for the closure, but it would change our
desired API to place the burden of fetching the correct callback on the
caller.
## Solution
Modify the `FunctionRegistry` to store registered functions as
`DynamicClosure<'static>` instead of `DynamicFunction` (now using
`IntoClosure` instead of `IntoFunction`).
Due to limitations in Rust and how function reflection works,
`DynamicClosure<'static>` is functionally equivalent to
`DynamicFunction`. And a normal function is considered a subset of
closures (it's a closure that doesn't capture anything), so there
shouldn't be any difference in usage: all functions that satisfy
`IntoFunction` should satisfy `IntoClosure`.
This means that the registration API introduced in #14098 should require
little-to-no changes on anyone following `main`.
### Closures vs Functions
One consideration here is whether we should keep closures and functions
separate.
This PR unifies them into `DynamicClosure<'static>`, but we can consider
splitting them up. The reasons we might want to do so are:
- Simplifies mental model and terminology (users don't have to
understand that functions turn into closures)
- If Rust ever improves its function model, we may be able to add
additional guarantees to `DynamicFunction` that make it useful to
separate the two
- Adding support for generic functions may be less confusing for users
since closures in Rust technically can't be generic
The reasons behind this PR's unification approach are:
- Reduces the number of methods needed on `FunctionRegistry`
- Reduces the number of lookups a user may have to perform (i.e.
"`get_function` or else `get_closure`")
- Establishes `DynamicClosure<'static>` as the de facto dynamic callable
(similar to how most APIs in Rust code tend to prefer `impl Fn() ->
String` over `fn() -> String`)
I'd love to hear feedback on this matter, and whether we should continue
with this PR's approach or switch to a split model.
## Testing
You can test locally by running:
```
cargo test --package bevy_reflect
```
---
## Showcase
Closures can now be registered into the `FunctionRegistry`:
```rust
let punct = String::from("!!!");
registry.register_with_name("my_crate::punctuate", move |text: String| {
format!("{}{}", text, punct)
});
```
# Objective
The `prepare_view_upscaling_pipelines` system has dozens of ambiguities,
which makes it harder to spot and prevent new ambiguities.
Closes https://github.com/bevyengine/bevy/issues/14770.
## Solution
Just exclude the system from ambiguity detection. See the linked issue
for more context on why this resolution was chosen.
## Testing
Running the `ambiguity_detection` example now reports dozens fewer
`Render` app ambiguities.
# Objective
- Add "Available on crate feature <image format> only." for docs of
image format related types/functions
- Add warning "WARN bevy_render::texture::image: feature "<image
format>" is not enabled" on load attempt
- Fixes#13468 .
## Solution
- Added #[cfg(feature = "<image format>")] for types and warn!("feature
\"<image format>\" is not enabled"); for ImageFormat enum conversions
## Testing
ran reproducing example from issue #13468 and saw in logs
`WARN bevy_render::texture::image: feature "exr" is not enabled`
generated docs with command `RUSTDOCFLAGS="-Zunstable-options
--cfg=docsrs" cargo +nightly doc --workspace --all-features --no-deps
--document-private-items --open` and saw
![image](https://github.com/bevyengine/bevy/assets/17225606/820262bb-b4e6-4a5e-a306-bddbe9c40852)
that docs contain `Available on crate feature <image format> only.`
marks
![image](https://github.com/bevyengine/bevy/assets/17225606/57463440-a2ea-435f-a2c2-50d34f7f55a9)
## Migration Guide
Image format related entities are feature gated, if there are
compilation errors about unknown names there are some of features in
list (`exr`, `hdr`, `basis-universal`, `png`, `dds`, `tga`, `jpeg`,
`bmp`, `ktx2`, `webp` and `pnm`) should be added.
# Objective
- Fixes#14655
## Solution
Rotation should happen first as this is more easier to conceptualize in
the mind: We rotate around the coordinate origin `Vec3::ZERO` and then
we just shift the geometry so that its center is exactly on the
specified position
## Testing && Showcase
Code:
```rust
gizmos.grid(
Vec3::ONE * 10.0,
Quat::from_rotation_x(PI / 3. * 2.),
UVec2::splat(20),
Vec2::new(2., 2.),
PURPLE,
);
gizmos.sphere(Vec3::ONE * 10.0, Quat::default(), 1.0, PURPLE);
```
Before picture:
![image](https://github.com/user-attachments/assets/7fea2e71-e62b-4763-9f9f-7a1ecd630ada)
After picture:
![image](https://github.com/user-attachments/assets/899dad64-010a-4e4b-86ae-53b85fef0bbc)
## Migration Guide
- Users might have to double check their already existing calls to all
the `grid` methods. It should be more intuitive now though.
# Objective
Fix#14771 by adding a `try_insert_if_new` method to the
`EntityCommands`
## Solution
This simply calls the `try_insert` function with `InsertMode::Keep`
## Testing
I did not add any test because `EntityCommands::try_insert` does not
seem to be tested either. I can add some if needed.
# Objective
Fixes#14736
## Solution
Enables feature `bevy_render` for dependency `bevy_gizmos` in
`bevy_dev_tools` cargo.
`bevy_dev_tools` has `bevy_render` as a required dependency, whereas it
is optional for `bevy_gizmos`. When building with no default features,
this causes gizmos to not compile with `bevy_render` features, meaning
some fields and code are not available. Since these features are
required in dev tools, it makes sense to ensure they are enabled. Making
`bevy_render` optional would introduce additional and potentially
unwanted change wake. in dev tools.
## Testing
Reproed and tested on Windows 10, issue originally reported on Ubuntu
and MacOS.
- Original issue command completed without error: `cargo c -p bevy
--no-default-features -F bevy_dev_tools`
- Ran full ci validations with `cargo run -p ci`
# Objective
Finish what we started in #14630. The Curve RFC is
[here](https://github.com/bevyengine/rfcs/blob/main/rfcs/80-curve-trait.md).
## Solution
This contains the rest of the library from my branch. The main things
added here are:
- Bulk sampling / resampling methods on `Curve` itself
- Data structures supporting the above
- The `cores` submodule that those data structures use to encapsulate
sample interpolation
The weirdest thing in here is probably `ChunkedUnevenCore` in `cores`,
which is not used by anything in the Curve library itself but which is
required for efficient storage of glTF animation curves. (See #13105.)
We can move it into a different PR if we want to; I don't have strong
feelings either way.
## Testing
New tests related to resampling are included. As I write this, I realize
we could use some tests in `cores` itself, so I will add some on this
branch before too long.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Robert Walter <26892280+RobWalt@users.noreply.github.com>
# Objective
This `apply_deferred` doesn't seem to have any effect, pointlessly
restricts parallelism and is responsible for a large number of system
order ambiguities. Spotted as part of #7386.
## Solution
Remove it.
This is the *only* manual apply_deferred in the code base currently.
## Testing
I've checked various UI examples and `split_screen`, and couldn't
discern any difference.
This looks like a remnant of a `(a, apply_deferred, b).chain()` pattern
where `b` got removed, leaving us with a weird vestige.
# Objective
Often there are reasons to insert some components (e.g. Transform)
separately from the rest of a bundle (e.g. PbrBundle). However `insert`
overwrites existing components, making this difficult.
See also issue #14397Fixes#2054.
## Solution
This PR adds the method `insert_if_new` to EntityMut and Commands, which
is the same as `insert` except that the old component is kept in case of
conflicts.
It also renames some internal enums (from `ComponentStatus::Mutated` to
`Existing`), to reflect the possible change in meaning.
## Testing
*Did you test these changes? If so, how?*
Added basic unit tests; used the new behavior in my project.
*Are there any parts that need more testing?*
There should be a test that the change time isn't set if a component is
not overwritten; I wasn't sure how to write a test for that case.
*How can other people (reviewers) test your changes? Is there anything
specific they need to know?*
`cargo test` in the bevy_ecs project.
*If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?*
Only tested on Windows, but it doesn't touch anything platform-specific.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Giacomo Stevanato <giaco.stevanato@gmail.com>
# Objective
`World::clear_entities` is ambiguous with all of the other systems in
`RenderSet::Cleanup` because it access `&mut World`.
## Solution
I've added another system set variant, and made sure that this runs
after everything else.
## Testing
The `ambiguity_detection` example
## Migration Guide
`World::clear_entities` is now part of `RenderSet::PostCleanup` rather
than `RenderSet::Cleanup`. Your cleanup systems should likely stay in
`RenderSet::Cleanup`.
## Additional context
Spotted when working on #7386: this was responsible for a large number
of ambiguities.
This should be removed if / when #14449 is merged: there's no need to
call `clear_entities` at all if the rendering world is retained!
# Objective
When an item in the transparent 2d phase fails to render, bevy crashes
with _"PassSpanScope::end was never called"_ instead of outputting the
actual error to the console. This PR fixes this so that phase errors are
output to the console. It also makes bevy not crash.
```
thread '<unnamed>' panicked at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/diagnostic/mod.rs:157:9:
PassSpanScope::end was never called
stack backtrace:
0: rust_begin_unwind
at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/std/src/panicking.rs:652:5
1: core::panicking::panic_fmt
at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/panicking.rs:72:14
2: <bevy_render::diagnostic::PassSpanGuard<R,P> as core::ops::drop::Drop>::drop
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/diagnostic/mod.rs:157:9
3: core::ptr::drop_in_place<bevy_render::diagnostic::PassSpanGuard<core::option::Option<alloc::sync::Arc<bevy_render::diagnostic::internal::DiagnosticsRecorder>>,bevy_render::render_phase::draw_state::TrackedRenderPass>>
at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/ptr/mod.rs:514:1
4: <bevy_core_pipeline::core_2d::main_transparent_pass_2d_node::MainTransparentPass2dNode as bevy_render::render_graph::node::ViewNode>::run
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_core_pipeline/src/core_2d/main_transparent_pass_2d_node.rs:75:9
5: <bevy_render::render_graph::node::ViewNodeRunner<T> as bevy_render::render_graph::node::Node>::run
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/render_graph/node.rs:406:9
6: bevy_render::renderer::graph_runner::RenderGraphRunner::run_graph
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/renderer/graph_runner.rs:226:21
7: bevy_render::renderer::graph_runner::RenderGraphRunner::run_graph
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/renderer/graph_runner.rs:233:21
8: bevy_render::renderer::graph_runner::RenderGraphRunner::run
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/renderer/graph_runner.rs:81:9
9: bevy_render::renderer::render_system
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_render/src/renderer/mod.rs:40:15
10: core::ops::function::FnMut::call_mut
at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/ops/function.rs:166:5
11: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
at /rustc/129f3b9964af4d4a709d1383930ade12dfe7c081/library/core/src/ops/function.rs:294:13
12: <Func as bevy_ecs::system::exclusive_function_system::ExclusiveSystemParamFunction<fn(F0) .> Out>>::run::call_inner
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_ecs/src/system/exclusive_function_system.rs:229:21
13: <Func as bevy_ecs::system::exclusive_function_system::ExclusiveSystemParamFunction<fn(F0) .> Out>>::run
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_ecs/src/system/exclusive_function_system.rs:232:17
14: <bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run::{{closure}}
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_ecs/src/system/exclusive_function_system.rs:124:23
15: bevy_ecs::world::World::last_change_tick_scope
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_ecs/src/world/mod.rs:2383:9
16: <bevy_ecs::system::exclusive_function_system::ExclusiveFunctionSystem<Marker,F> as bevy_ecs::system::system::System>::run
at /Users/brianreavis/Repositories/project/bevy/crates/bevy_ecs/src/system/exclusive_function_system.rs:116:9
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```
## Solution
Matched the behavior of the other render phases ([like
here](9ca5540b75/crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs (L98-L101)))
# Objective
- Sometimes some method or function takes an owned `Query`, but we don't
want to give up ours;
- transmuting it technically a solution, but it more costly than
necessary.
- Make query iterators more flexible
- this would allow the equivalent of
`slice::split_first`/`slice::split_first_mut` for query iterators
- helps with requests like #14685
## Solution
- Add a way for reborrowing queries, that is going from a `&'a mut
Query<'w, 's, D, F>` to a `Query<'a, 's, D, F>`:
- this is safe because the original query will be borrowed while the new
query exists and thus no aliased access can happen;
- it's basically the equivalent of going from `&'short mut &'long mut T`
to `&'short mut T` the the compiler automatically implements.
- Add a way for getting the remainder of a query iterator:
- this is interesting also because the original iterator keeps its
position, which was not possible before;
- this in turn requires a way to reborrow query fetches, which I had to
add to `WorldQuery`.
## Showcase
- You can now reborrow a `Query`, getting an equivalent `Query` with a
shorter lifetime. Previously this was possible for read-only queries by
using `Query::to_readonly`, now it's possible for mutable queries too;
- You can now separately iterate over the remainder of `QueryIter`.
## Migration Guide
- `WorldQuery` now has an additional `shrink_fetch` method you have to
implement if you were implementing `WorldQuery` manually.
# Objective
`Res` and `ResMut` perform redundant lookups of the resource storage,
first to initialize the `ArchetypeComponentId` and then to retrieve it.
## Solution
Use the `archetype_component_id` returned from
`initialize_resource_internal` to avoid an extra lookup and `unwrap()`.
# Objective
fix#14742
## Solution
the issue arises because "finished" animations (where current time >=
last keyframe time) are not applied at all.
when transitioning from a finished animation to another later-indexed
anim, the transition kind-of works because the finished anim is skipped,
then the new anim is applied with a lower weight (weight / total_weight)
when transitioning from a finished animation to another earlier-indexed
anim, the transition is instant as the new anim is applied with 1.0 (as
weight == total_weight for the first applied), then the finished
animation is skipped.
to fix this we can always apply every animation based on the nearest 2
keyframes, and clamp the interpolation between them to [0,1].
pros:
- finished animations can be transitioned out of correctly
- blended animations where some curves have a last-keyframe before the
end of the animation will blend properly
- animations will actually finish on their last keyframe, rather than a
fraction of a render-frame before the end
cons:
- we have to re-apply finished animations every frame whether it's
necessary or not. i can't see a way to avoid this.