# Objective
- `MeshPickingBackend` and `SpritePickingBackend` do not have the
`Plugin` suffix
- `DefaultPickingPlugins` is masquerading as a `Plugin` when in reality
it should be a `PluginGroup`
- Fixes#16081.
## Solution
- Rename some structures:
|Original Name|New Name|
|-|-|
|`MeshPickingBackend`|`MeshPickingPlugin`|
|`MeshPickingBackendSettings`|`MeshPickingSettings`|
|`SpritePickingBackend`|`SpritePickingPlugin`|
|`UiPickingBackendPlugin`|`UiPickingPlugin`|
- Make `DefaultPickingPlugins` a `PluginGroup`.
- Because `DefaultPickingPlugins` is within the `DefaultPlugins` plugin
group, I also added support for nested plugin groups to the
`plugin_group!` macro.
## Testing
- I used ripgrep to ensure all references were properly renamed.
- For the `plugin_group!` macro, I used `cargo expand` to manually
inspect the expansion of `DefaultPlugins`.
---
## Migration Guide
> [!NOTE]
>
> All 3 of the changed structures were added after 0.14, so this does
not need to be included in the 0.14 to 0.15 migration guide.
- `MeshPickingBackend` is now named `MeshPickingPlugin`.
- `MeshPickingBackendSettings` is now named `MeshPickingSettings`.
- `SpritePickingBackend` is now named `SpritePickingPlugin`.
- `UiPickingBackendPlugin` is now named `UiPickingPlugin`.
- `DefaultPickingPlugins` is now a a `PluginGroup` instead of a
`Plugin`.
# Objective
This PR introduces an `AsyncSeekForwardExt` trait, which I forgot in my
previous PR #14194.
This new trait is analogous to `AsyncSeekExt` and allows all
implementors of `AsyncSeekForward` to directly use the `seek_forward`
function in async contexts.
## Solution
- Implement a new `AsyncSeekForwardExt` trait
- Automatically implement this trait for all types that implement
`AsyncSeekForward`
## Showcase
This new trait allows a similar API to the previous Bevy version:
```rust
#[derive(Default)]
struct UniverseLoader;
#[derive(Asset, TypePath, Debug)]
struct JustALilAsteroid([u8; 128]);
impl AssetLoader for UniverseLoader {
type Asset = JustALilAsteroid;
type Settings = ();
type Error = std::io::Error;
async fn load<'a>(
&'a self,
reader: &'a mut Reader<'a>,
_settings: &'a Self::Settings,
_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
// read the asteroids entry table
let entry_offset: u64 = /* ... */;
let current_offset: u64 = reader.seek_forward(0).await?;
// jump to the entry
reader.seek_forward(entry_offset - current_offset).await?;
let mut asteroid_buf = [0; 128];
reader.read_exact(&mut asteroid_buf).await?;
Ok(JustALilAsteroid(asteroid_buf))
}
fn extensions(&self) -> &[&str] {
&["celestial"]
}
}
```
The two additional linear texture samplers that PCSS added caused us to
blow past the limit on Apple Silicon macOS and WebGL. To fix the issue,
this commit adds a `--feature pbr_pcss` feature gate that disables PCSS
if not present.
Closes#15345.
Closes#15525.
Closes#15821.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
The PCSS PR #13497 increased the size of clusterable objects from 64
bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
blew past the 16kB limit on WebGL 2. This commit fixes the issue by
lowering the maximum number of clusterable objects to 204, which puts us
under the 16kB limit again.
Closes#15998.
# Objective
- Follow up on #16044
- `extract_uinode_borders` uses `bevy_hierarchy` directly instead of
going through the traversal utilities, meaning it won't handle
`GhostNode`s properly.
## Solution
- Replaced the use of `bevy_hierarchy::Parent` with
`UIChildren::get_parent`
## Testing
- Ran the `overflow` example, clipping looks ok.
---
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
1. Nodes with `Display::None` set are removed from the layout and have
no position or size. Outlines should not be drawn for a node with
`Display::None` set.
2. The outline and border colors are checked for transparency together.
If only one of the two is transparent, both will get queued.
3. The `node.is_empty()` check is insufficient to check if a border is
present since a non-zero sized node can have a zero width border.
## Solution
1. Add a check to `extract_uinode_borders` and ignore the node if
`Display::None` is set.
2. Filter the border and outline optional components by
`is_fully_transparent`.
3. Check if all the border widths are zero instead.
## Testing
I added dark cyan outlines around the left and right sections in the
`display_and_visibility` example. If you run the example and set the
outermost node to `Display::None` on the right, then you'll see the that
the outline on the left disappears.
# Objective
Fixes#16006
## Solution
We currently re-export `cosmic_text`, which is seemingly motivated by
the desire to use `cosmic_text::FontSystem` in `bevy_text` public APIs
instead of our `CosmicFontSystem` resource wrapper type.
This change makes `bevy_text` a "true" abstraction over `cosmic_text`
(it in fact, was already built to be that way generally and has this one
"leak").
This allows us to remove the `cosmic_text` re-export, which helps clean
up the Rust Analyzer imports and generally makes this a "cleaner" API.
# Objective
- Make the meshlet fill cluster buffers pass slightly faster
- Address https://github.com/bevyengine/bevy/issues/15920 for meshlets
- Added PreviousGlobalTransform as a required meshlet component to avoid
extra archetype moves, slightly alleviating
https://github.com/bevyengine/bevy/issues/14681 for meshlets
- Enforce that MeshletPlugin::cluster_buffer_slots is not greater than
2^25 (glitches will occur otherwise). Technically this field controls
post-lod/culling cluster count, and the issue is on pre-lod/culling
cluster count, but it's still valid now, and in the future this will be
more true.
Needs to be merged after https://github.com/bevyengine/bevy/pull/15846
and https://github.com/bevyengine/bevy/pull/15886
## Solution
- Old pass dispatched a thread per cluster, and did a binary search over
the instances to find which instance the cluster belongs to, and what
meshlet index within the instance it is.
- New pass dispatches a workgroup per instance, and has the workgroup
loop over all meshlets in the instance in order to write out the cluster
data.
- Use a push constant instead of arrayLength to fix the linked bug
- Remap 1d->2d dispatch for software raster only if actually needed to
save on spawning excess workgroups
## Testing
- Did you test these changes? If so, how?
- Ran the meshlet example, and an example with 1041 instances of 32217
meshlets per instance. Profiled the second scene with nsight, went from
0.55ms -> 0.40ms. Small savings. We're pretty much VRAM bandwidth bound
at this point.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the meshlet example
## Changelog (non-meshlets)
- PreviousGlobalTransform now implements the Default trait
Take a bunch more improvements from @zeux's nanite.cpp code.
* Use position-only vertices (discard other attributes) to determine
meshlet connectivity for grouping
* Rather than using the lock borders flag when simplifying meshlet
groups, provide the locked vertices ourselves. The lock borders flag
locks the entire border of the meshlet group, but really we only want to
lock the edges between meshlet groups - outwards facing edges are fine
to unlock. This gives a really significant increase to the DAG quality.
* Add back stuck meshlets (group has only a single meshlet,
simplification failed) to the simplification queue to allow them to get
used later on and have another attempt at simplifying
* Target 8 meshlets per group instead of 4 (second biggest improvement
after manual locks)
* Provide a seed to metis for deterministic meshlet building
* Misc other improvements
We can remove the usage of unsafe after the next upstream meshopt
release, but for now we need to use the ffi function directly. I'll do
another round of improvements later, mainly attribute-aware
simplification and using spatial weights for meshlet grouping.
Need to merge https://github.com/bevyengine/bevy/pull/15846 first.
# Objective
- I made a mistake in #15902, specifically [this
diff](e2faedb99c)
-- the `point_light_count` variable is used for all point lights, not
just shadow mapped ones, so I cannot add `.min(max_texture_cubes)`
there. (Despite `spot_light_count` having `.min(..)`)
It may have broken code like this (where `index` is index of
`point_light` vec):
9930df83ed/crates/bevy_pbr/src/render/light.rs (L848-L850)
and also causes panic here:
9930df83ed/crates/bevy_pbr/src/render/light.rs (L1173-L1174)
## Solution
- Adds `.min(max_texture_cubes)` directly to the loop where texture
views for point lights are created.
## Testing
- `lighting` example (with the directional light removed; original
example doesn't crash as only 1 directional-or-spot light in total is
shadow-mapped on webgl) no longer crashes on webgl
# Objective
1. Prevent weird glitches with stray pixels scattered around the scene
![image](https://github.com/user-attachments/assets/f12adb38-5996-4dc7-bea6-bd326b7317e1)
2. Prevent weird glitchy full-screen triangles that pop-up and destroy
perf (SW rasterizing huge triangles is slow)
![image](https://github.com/user-attachments/assets/d3705427-13a5-47bc-a54b-756f0409da0b)
## Solution
1. Use floating point math in the SW rasterizer bounding box calculation
to handle negative verticss, and add backface culling
2. Force hardware raster for clusters that clip the near plane, and let
the hardware rasterizer handle the clipping
I also adjusted the SW rasterizer threshold to < 64 pixels (little bit
better perf in my test scene, but still need to do a more comprehensive
test), and enabled backface culling for the hardware raster pipeline.
## Testing
- Did you test these changes? If so, how?
- Yes, on an example scene. Issues no longer occur.
- Are there any parts that need more testing?
- No.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the meshlet example.
# Objective
- bevy_remote Cargo.toml file references a readme that doesn't exist
- This is blocking releasing the rc
## Solution
- Remove the reference
# Objective
fixes#15502
Clipped borders and outlines aren't drawn correctly.
### Borders aren't clipped
Spawn two nodes with the same dimensions and border thickness, but clip
on of the nodes so that only its top left quarter is visible:
<img width="194" alt="clip"
src="https://github.com/user-attachments/assets/2d3f6d28-aa20-44df-967a-677725828294">
You can see that instead of clipping the border, instead the border is
scaled to fit inside of the unclipped section.
```rust
use bevy::color::palettes::css::BLUE;
use bevy::prelude::*;
use bevy::winit::WinitSettings;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(WinitSettings::desktop_app())
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn(Node {
width: Val::Percent(100.),
height: Val::Percent(100.),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..Default::default()
})
.with_children(|commands| {
commands
.spawn(Node {
column_gap: Val::Px(10.),
..Default::default()
})
.with_children(|commands| {
commands
.spawn(Node {
width: Val::Px(100.),
height: Val::Px(100.),
overflow: Overflow::clip(),
..Default::default()
})
.with_child((
Node {
position_type: PositionType::Absolute,
width: Val::Px(100.),
height: Val::Px(100.),
border: UiRect::all(Val::Px(10.)),
..Default::default()
},
BackgroundColor(Color::WHITE),
BorderColor(BLUE.into()),
));
commands
.spawn(Node {
width: Val::Px(50.),
height: Val::Px(50.),
overflow: Overflow::clip(),
..Default::default()
})
.with_child((
Node {
position_type: PositionType::Absolute,
width: Val::Px(100.),
height: Val::Px(100.),
border: UiRect::all(Val::Px(10.)),
..Default::default()
},
BackgroundColor(Color::WHITE),
BorderColor(BLUE.into()),
));
});
});
}
```
You can also see this problem in the `overflow` example. If you hover
over any of the clipped nodes you'll see that the outline only wraps the
visible section of the node
### Outlines are clipped incorrectly
A UI nodes Outline's are drawn outside of its bounds, so applying the
local clipping rect to the outline doesn't make any sense.
Instead an `Outline` should be clipped using its parent's clipping rect.
## Solution
* Pass the `point` value into the vertex shader instead of calculating
it in the shader.
* In `extract_uinode_borders` use the parents clipping rect when
clipping outlines.
The extra parameter isn't a great solution I think, but I wanted to fix
borders for the 0.15 release and this is the most minimal approach I
could think of without replacing the whole shader and prepare function.
## Showcase
<img width="149" alt="clipp"
src="https://github.com/user-attachments/assets/19fbd3cc-e7cd-42e1-a5e0-fd92aad04dcd">
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Less code
- Better iterator (implements `size_hint` for example)
## Solution
- Use `either`
- This change is free because `bevy_animation` depends on `bevy_asset`,
which already depends on `either`
## Testing
CI
# Objective
Bevy seems to want to standardize on "American English" spellings. Not
sure if this is laid out anywhere in writing, but see also #15947.
While perusing the docs for `typos`, I noticed that it has a `locale`
config option and tried it out.
## Solution
Switch to `en-us` locale in the `typos` config and run `typos -w`
## Migration Guide
The following methods or fields have been renamed from `*dependants*` to
`*dependents*`.
- `ProcessorAssetInfo::dependants`
- `ProcessorAssetInfos::add_dependant`
- `ProcessorAssetInfos::non_existent_dependants`
- `AssetInfo::dependants_waiting_on_load`
- `AssetInfo::dependants_waiting_on_recursive_dep_load`
- `AssetInfos::loader_dependants`
- `AssetInfos::remove_dependants_and_labels`
Use the new `disqualified` crate in `QueryEntityError` to make the error
message more readable.
---
## Showcase
Old:
QueryDoesNotMatch(0v1 with components my_game::main::foo::A,
my_game::main::foo::B, bevy_pbr::light::point_light::PointLight,
bevy_render::primitives::CubemapFrusta,
bevy_pbr::bundle::CubemapVisibleEntities,
bevy_transform::components::transform::Transform,
bevy_transform::components::global_transform::GlobalTransform,
bevy_render::view::visibility::Visibility,
bevy_render::view::visibility::InheritedVisibility,
bevy_render::view::visibility::ViewVisibility,
bevy_render::sync_world::SyncToRenderWorld)
New:
QueryDoesNotMatch(0v1 with components A, B, PointLight, CubemapFrusta,
CubemapVisibleEntities, Transform, GlobalTransform, Visibility,
InheritedVisibility, ViewVisibility, SyncToRenderWorld)
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Make compiler output more helpful when running `cargo check -p
bevy_mesh`. Currently it contains a lot of unreachable patterns/code
warnings due to features disabled by default.
## Solution
Mute the warnings.
## Testing
CI
# Objective
```
cargo check -p bevy_reflect
```
outputs a lot of warnings like:
```
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> crates/bevy_reflect/src/impls/std.rs:223:13
|
223 | impl_type_path!($ty);
| ^-------------------
| |
| `TypePath` is not local
| move the `impl` block outside of this constant `_` and up 2 bodies
...
346 | / impl_reflect_for_atomic!(
347 | | ::core::sync::atomic::AtomicIsize,
| | --------------------------------- `AtomicIsize` is not local
348 | | ::core::sync::atomic::Ordering::SeqCst
349 | | );
| |_- in this macro invocation
|
= note: the macro `impl_type_path` defines the non-local `impl`, and may need to be changed
= note: the macro `impl_type_path` may come from an old version of the `bevy_reflect_derive` crate, try updating your dependency with `cargo update -p bevy_reflect_derive`
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration for the purpose of this lint
= note: `#[warn(non_local_definitions)]` on by default
= note: this warning originates in the macro `impl_type_path` which comes from the expansion of the macro `impl_reflect_for_atomic` (in Nightly builds, run with -Z macro-backtrace for more info)
```
## Solution
Move `impl_type_path!` into global scope. Warnings no longer pop up.
## Testing
CI
# Objective
Making work with `Indices` struct easier. Currently when building
indices in some quick-and-dirty code we need to do matches and handle
enum variants.
## Solution
`Indices::push` utility which works transparently with `U16` and `U32`
variants.
## Testing
Unit test added.
# Objective
Built-in observers & events should be `Reflect` so that components that
interact with them can be serialized in scenes. This is a similar pr to
#14259.
## Objective
Be able to depend on the crate for the types without bringing in
`smol-hyper` and other http dependencies.
## Solution
Create a new `HTTP` feature that is enabled by default.
# Objective
Make UI rendering optional.
Quite a few people have been experimenting with using Bevy UI for layout
and interaction but replacing the rendering with `bevy_prototype_lyon`
or whatever. It's awkward to do though as there is no way to disable the
existing UI rendering requiring users to create their own custom node
bundles and components. Also, you can't replace the UI's shader and a
number of other things.
This PR makes the setup and initialization of UI rendering for the
RenderApp optional. Then you can do whatever you want by replacing
`build_ui_render` with your own function. For instance, one that loads a
custom shader.
The UI layout and interaction components are still updated as normal.
## Solution
Add a field `enable_rendering` to `UiPlugin`.
Only call `build_ui_render` and initialize the `UiPipeline` if
`enable_rendering` is false.
I thought about implementing a "bevy_ui_render" feature but suspect
everything is too tightly coupled atm and it would be very fragile.
Similar to the struggles with the "bevy_text" feature but worse.
---
## Changelog
`UiPlugin`
* Added a bool field `enable_rendering`.
* Only calls `build_ui_render` and initializes the `UiPipeline` if
`enable_rendering` is true.
## Migration Guide
`UiPlugin` has a new field `enable_rendering`. If set to false, the UI's
rendering systems won't be added to the `RenderApp` and no UI elements
will be drawn. The layout and interaction components will still be
updated as normal.
# Objective
Adding a `WinitPlugin` to a `MinimalPlugins` setup is a bit tricky and
confusing due to having a terrible error message and no examples in the
repo.
## Solution
Document what you need to add.
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/15871
(Camera is done in #15946)
## Solution
- Do the same as #15904 for other extraction systems
- Added missing `SyncComponentPlugin` for DOF, TAA, and SSAO
(According to the
[documentation](https://dev-docs.bevyengine.org/bevy/render/sync_component/struct.SyncComponentPlugin.html),
this plugin "needs to be added for manual extraction implementations."
We may need to check this is done.)
## Testing
Modified example locally to add toggles if not exist.
- [x] DOF - toggling DOF component and perspective in `depth_of_field`
example
- [x] TAA - toggling `Camera.is_active` and TAA component
- [x] clusters - not entirely sure, toggling `Camera.is_active` in
`many_lights` example (no crash/glitch even without this PR)
- [x] previous_view - toggling `Camera.is_active` in `skybox` (no
crash/glitch even without this PR)
- [x] lights - toggling `Visibility` of `DirectionalLight` in `lighting`
example
- [x] SSAO - toggling `Camera.is_active` and SSAO component in `ssao`
example
- [x] default UI camera view - toggling `Camera.is_active` (nop without
#15946 because UI defaults to some camera even if `DefaultCameraView` is
not there)
- [x] volumetric fog - toggling existence of volumetric light. Looks
like optimization, no change in behavior/visuals
# Objective
Switch to retained render world causes the extracted cameras in render
world to not be removed until camera in main world is despawned. When
extracting data from main world inactive cameras are skipped. Therefore
camera that was active and became inactive has a retained
`ExtractedCamera` component from previous frames (when it was active)
and is processed the same way as if it were active (there is no `active`
field on `ExtractedCamera`). This breakes switching between cameras in
`render_primitives` example.
Fixes#15822
## Solution
Fix it by removing `ExtractedCamera` and related components from
inactive cameras.
Note that despawning inactive camera seems to be bad option because they
are spawned using `SyncToRenderWorld` component.
## Testing
Switching camera in `render_primitives` example now works correctly.
---------
Co-authored-by: akimakinai <105044389+akimakinai@users.noreply.github.com>
# Objective
- The depth test was only using the final depth but it should be testing
each fragments
- Fully transparent fragments should not be added to the list
## Solution
- Test each fragment after sorting
## Testing
before:
TODO
after:
TODO
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/13552
## Solution
- Thanks for the guidance from @DGriffin91, the current solution is to
transmit the light_map through the emissive channel to avoid increasing
the bandwidth of deferred shading.
- <del>Store lightmap sample result into G-Buffer and pass them into the
`Deferred Lighting Pipeline`, therefore we can get the correct indirect
lighting via the `apply_pbr_lighting` function.</del>
- <del>The original G-Buffer lacks storage for lightmap data, therefore
a new buffer is added. We can only use Rgba16Uint here due to the
32-byte limit on the render targets.</del>
## Testing
- Need to test all the examples that contains a prepass, with both the
forward and deferred rendering mode.
- I have tested the ones below.
- `lightmaps` (adjust the code based on the issue and check the
rendering result)
- `transmission` (it contains a prepass)
- `ssr` (it also uses the G-Bufffer)
- `meshlet` (forward and deferred)
- `pbr`
## Showcase
By updating the `lightmaps` example to use deferred rendering, this pull
request enables correct rendering result of the Cornell Box.
```
diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs
index 564a3162b..11a748fba 100644
--- a/examples/3d/lightmaps.rs
+++ b/examples/3d/lightmaps.rs
@@ -1,12 +1,14 @@
//! Rendering a scene with baked lightmaps.
-use bevy::pbr::Lightmap;
+use bevy::core_pipeline::prepass::DeferredPrepass;
+use bevy::pbr::{DefaultOpaqueRendererMethod, Lightmap};
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(AmbientLight::NONE)
+ .insert_resource(DefaultOpaqueRendererMethod::deferred())
.add_systems(Startup, setup)
.add_systems(Update, add_lightmaps_to_meshes)
.run();
@@ -19,10 +21,12 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..default()
});
- commands.spawn(Camera3dBundle {
- transform: Transform::from_xyz(-278.0, 273.0, 800.0),
- ..default()
- });
+ commands
+ .spawn(Camera3dBundle {
+ transform: Transform::from_xyz(-278.0, 273.0, 800.0),
+ ..default()
+ })
+ .insert(DeferredPrepass);
}
fn add_lightmaps_to_meshes(
```
<img width="1280" alt="image"
src="https://github.com/user-attachments/assets/17fd3367-61cc-4c23-b956-e7cfc751af3c">
## Emissive Issue
**The emissive light object appears incorrectly rendered because the
alpha channel of emission is set to 1 in deferred rendering and 0 in
forward rendering, leading to different emissive light result. Could
this be a bug?**
```wgsl
// pbr_deferred_functions.wgsl - pbr_input_from_deferred_gbuffer
let emissive = rgb9e5::rgb9e5_to_vec3_(gbuffer.g);
if ((pbr.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
pbr.material.base_color = vec4(emissive, 1.0);
pbr.material.emissive = vec4(vec3(0.0), 1.0);
} else {
pbr.material.base_color = vec4(pow(base_rough.rgb, vec3(2.2)), 1.0);
pbr.material.emissive = vec4(emissive, 1.0);
}
// pbr_functions.wgsl - apply_pbr_lighting
emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a);
```
---------
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
# Objective
Continue improving the user experience of our UI Node API in the
direction specified by [Bevy's Next Generation Scene / UI
System](https://github.com/bevyengine/bevy/discussions/14437)
## Solution
As specified in the document above, merge `Style` fields into `Node`,
and move "computed Node fields" into `ComputedNode` (I chose this name
over something like `ComputedNodeLayout` because it currently contains
more than just layout info. If we want to break this up / rename these
concepts, lets do that in a separate PR). `Style` has been removed.
This accomplishes a number of goals:
## Ergonomics wins
Specifying both `Node` and `Style` is now no longer required for
non-default styles
Before:
```rust
commands.spawn((
Node::default(),
Style {
width: Val::Px(100.),
..default()
},
));
```
After:
```rust
commands.spawn(Node {
width: Val::Px(100.),
..default()
});
```
## Conceptual clarity
`Style` was never a comprehensive "style sheet". It only defined "core"
style properties that all `Nodes` shared. Any "styled property" that
couldn't fit that mold had to be in a separate component. A "real" style
system would style properties _across_ components (`Node`, `Button`,
etc). We have plans to build a true style system (see the doc linked
above).
By moving the `Style` fields to `Node`, we fully embrace `Node` as the
driving concept and remove the "style system" confusion.
## Next Steps
* Consider identifying and splitting out "style properties that aren't
core to Node". This should not happen for Bevy 0.15.
---
## Migration Guide
Move any fields set on `Style` into `Node` and replace all `Style`
component usage with `Node`.
Before:
```rust
commands.spawn((
Node::default(),
Style {
width: Val::Px(100.),
..default()
},
));
```
After:
```rust
commands.spawn(Node {
width: Val::Px(100.),
..default()
});
```
For any usage of the "computed node properties" that used to live on
`Node`, use `ComputedNode` instead:
Before:
```rust
fn system(nodes: Query<&Node>) {
for node in &nodes {
let computed_size = node.size();
}
}
```
After:
```rust
fn system(computed_nodes: Query<&ComputedNode>) {
for computed_node in &computed_nodes {
let computed_size = computed_node.size();
}
}
```
Resolves#15968. Since this feature never worked, and enabling it in the
`image` crate requires system dependencies, we've decided that it's best
to just remove it and let other plugin crates offer support for it as
needed.
## Migration Guide
AVIF images are no longer supported. They never really worked, and
require system dependencies (libdav1d) to work correctly, so, it's
better to simply offer this support via an unofficial plugin instead as
needed. The corresponding types have been removed from Bevy to account
for this.
# Objective
Fixes#15791.
As raised in #11022, scaling orthographic cameras is confusing! In Bevy
0.14, there were multiple completely redundant ways to do this, and no
clear guidance on which to use.
As a result, #15075 removed the `scale` field from
`OrthographicProjection` completely, solving the redundancy issue.
However, this resulted in an unintuitive API and a painful migration, as
discussed in #15791. Users simply want to change a single parameter to
zoom, rather than deal with the irrelevant details of how the camera is
being scaled.
## Solution
This PR reverts #15075, and takes an alternate, more nuanced approach to
the redundancy problem. `ScalingMode::WindowSize` was by far the biggest
offender. This was the default variant, and stored a float that was
*fully* redundant to setting `scale`.
All of the other variants contained meaningful semantic information and
had an intuitive scale. I could have made these unitless, storing an
aspect ratio, but this would have been a worse API and resulted in a
pointlessly painful migration.
In the course of this work I've also:
- improved the documentation to explain that you should just set `scale`
to zoom cameras
- swapped to named fields for all of the variants in `ScalingMode` for
more clarity about the parameter meanings
- substantially improved the `projection_zoom` example
- removed the footgunny `Mul` and `Div` impls for `ScalingMode`,
especially since these no longer have the intended effect on
`ScalingMode::WindowSize`.
- removed a rounding step because this is now redundant 🎉
## Testing
I've tested these changes as part of my work in the `projection_zoom`
example, and things seem to work fine.
## Migration Guide
`ScalingMode` has been refactored for clarity, especially on how to zoom
orthographic cameras and their projections:
- `ScalingMode::WindowSize` no longer stores a float, and acts as if its
value was 1. Divide your camera's scale by any previous value to achieve
identical results.
- `ScalingMode::FixedVertical` and `FixedHorizontal` now use named
fields.
---------
Co-authored-by: MiniaczQ <xnetroidpl@gmail.com>
# Objective
- Fixes#15963
## Solution
- Implement `TryFrom<Polygon<N> for ConvexPolygon<N>`
- Implement `From<ConvexPolygon<N>> for Polygon<N>`
- Remove `pub` from `vertices`
- Add `ConvexPolygon::vertices()` to get read only access to the
vertices of a convex polygon.
# Objective
As discussed in #15341, ghost nodes are a contentious and experimental
feature. In the interest of enabling ecosystem experimentation, we've
decided to keep them in Bevy 0.15.
That said, we don't use them internally, and don't expect third-party
crates to support them. If the experimentation returns a negative result
(they aren't very useful, an alternative design is preferred etc) they
will be removed.
We should clearly communicate this status to users, and make sure that
users don't use ghost nodes in their projects without a very clear
understanding of what they're getting themselves into.
## Solution
To make life easy for users (and Bevy), `GhostNode` and all associated
helpers remain public and are always available.
However, actually constructing these requires enabling a feature flag
that's clearly marked as experimental. To do so, I've added a
meaningless private field.
When the feature flag is enabled, our constructs (`new` and `default`)
can be used. I've added a `new` constructor, which should be preferred
over `Default::default` as that can be readily deprecated, allowing us
to prompt users to swap over to the much nicer `GhostNode` syntax once
this is a unit struct again.
Full credit: this was mostly @cart's design: I'm just implementing it!
## Testing
I've run the ghost_nodes example and it fails to compile without the
feature flag. With the feature flag, it works fine :)
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Fixes#15834
## Migration Guide
The APIs of `Time`, `Timer` and `Stopwatch` have been cleaned up for
consistency with each other and the standard library's `Duration` type.
The following methods have been renamed:
- `Stowatch::paused` -> `Stopwatch::is_paused`
- `Time::elapsed_seconds` -> `Time::elasped_secs` (including `_f64` and
`_wrapped` variants)
# Objective
- UI materials reserve too much capacity in a vec: for every node in the
transparent phase, it reserves enough memory to store all the nodes
- Update #10437
## Solution
- Only reserve extra memory if there's not enough
- Only reserve the needed memory, not more
# Objective
In `queue_shadows`, the `UiBoxShadows` option is unwrapped incorrectly
which results in the number of shadow samples being set to
`u32::default()` instead of `UiBoxShadows::default()` if the camera
entity doesn't have the component.
## Solution
Just use `unwrap_or_default` directly without `map`.
# Objective
Remove `bevy-ui`'s non-functional "bevy_text" feature.
Fixes#15900
## Solution
Remove all the "bevy_text" cfg gates.
I tried to fix it at first but couldn't figure it out. I'll happily
withdraw this in favour of another PR that gets the feature gate
working.
# Objective
`TextFont` and `TextColor` is not registered in the app type registry
and serializing a scene with a a `Text2d` doesn't save the color and
font of the text entity.
## Solution
register `TextFont` and `TextColor` in the type registry
# Objective
Limited implementation of the CSS property `overflow-clip-margin`
https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-margin
Allows you to control the visible area for clipped content when using
overfllow-clip, -hidden, or -scroll and expand it with a margin.
Based on #15442Fixes#15468
## Solution
Adds a new field to Style: `overflow_clip_margin: OverflowClipMargin`.
The field is ignored unless overflow-clip, -hidden or -scroll is set on
at least one axis.
`OverflowClipMargin` has these associated constructor functions:
```
pub const fn content_box() -> Self;
pub const fn padding_box() -> Self;
pub const fn border_box() -> Self;
```
You can also use the method `with_margin` to increases the size of the
visible area:
```
commands
.spawn(NodeBundle {
style: Style {
width: Val::Px(100.),
height: Val::Px(100.),
padding: UiRect::all(Val::Px(20.)),
border: UiRect::all(Val::Px(5.)),
overflow: Overflow::clip(),
overflow_clip_margin: OverflowClipMargin::border_box().with_margin(25.),
..Default::default()
},
border_color: Color::BLACK.into(),
background_color: GRAY.into(),
..Default::default()
})
```
`with_margin` expects a length in logical pixels, negative values are
clamped to zero.
## Notes
* To keep this PR as simple as possible I omitted responsive margin
values support. This could be added in a follow up if we want it.
* CSS also supports a `margin-box` option but we don't have access to
the margin values in `Node` so it's probably not feasible to implement
atm.
## Testing
```cargo run --example overflow_clip_margin```
<img width="396" alt="overflow-clip-margin" src="https://github.com/user-attachments/assets/07b51cd6-a565-4451-87a0-fa079429b04b">
## Migration Guide
Style has a new field `OverflowClipMargin`. It allows users to set the visible area for clipped content when using overflow-clip, -hidden, or -scroll and expand it with a margin.
There are three associated constructor functions `content_box`, `padding_box` and `border_box`:
* `content_box`: elements painted outside of the content box area (the innermost part of the node excluding the padding and border) of the node are clipped. This is the new default behaviour.
* `padding_box`: elements painted outside outside of the padding area of the node are clipped.
* `border_box`: elements painted outside of the bounds of the node are clipped. This matches the behaviour from Bevy 0.14.
There is also a `with_margin` method that increases the size of the visible area by the given number in logical pixels, negative margin values are clamped to zero.
`OverflowClipMargin` is ignored unless overflow-clip, -hidden or -scroll is also set on at least one axis of the UI node.
---------
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
# Objective
- This is a followup to #15812.
## Solution
I just deleted the `COUNT` const and replaced it. I didn't realize for
loops are not const yet, so improving the other const variables is not
obvious.
Note: `slice::len` has been const since Rust 1.39, so we're not relying
on a brand new feature or anything.
## Testing
- It builds!
# Objective
On HEAD, `bevy_color` does not compile on its own with `--all-features`
enabled. This PR fixes that.
## Solution
- Added the `curve` feature on `bevy_math` to `bevy_color`.
- Added the `serialize` feature on `bevy_math` to
`bevy_color/serialize`.
## Testing
- Compiled with `cargo b -p bevy_color --all-features` on HEAD and on
this PR: it fails to compile on HEAD but compiles with this PR.
# Objective
- `C: ExtractComponent` inserts `C::Out` instead of `C`, so we need to
remove `C::Out`. cc #15904.
## Solution
- `C` -> `C::Out`
## Testing
- CAS has `<ContrastAdaptiveSharpening as ExtractComponent>::Out =
(DenoiseCas, CasUniform)`. Setting its strength to zero correctly
removes the effect after this change.
# Objective
Add an example for the new drag move and drag resize introduced by PR
#15674 and fix#15734.
## Solution
I created an example that allows the user to exercise drag move and drag
resize separately. The user can also choose what direction the resize
works in.
![Screenshot 2024-10-10 at 4 06
43 AM](https://github.com/user-attachments/assets/1da558ab-a80f-49af-8b7d-bb635b0f038f)
### Name
The example is called `window_drag_move`. Happy to have that
bikeshedded.
### Contentious Refactor?
This PR removed the `ResizeDirection` enumeration in favor of using
`CompassOctant` which had the same variants. Perhaps this is
contentious.
### Unsafe?
In PR #15674 I mentioned that `start_drag_move()` and
`start_drag_resize()`'s requirement to only be called in the presence of
a left-click looks like a compiler-unenforceable contract that can cause
intermittent panics when not observed, so perhaps the functions should
be marked them unsafe. **I have not made that change** here since I
didn't see a clear consensus on that.
## Testing
I exercised this on x86 macOS. However, winit for macOS does not support
drag resize. It reports a good error when `start_drag_resize()` is
called. I'd like to see it tested on Windows and Linux.
---
## Showcase
Example window_drag_move shows how to drag or resize a window without
decoration.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Make `StableInterpolate` "just work" on tuples whose parts are each
`StableInterpolate` types. These types arise notably through
`Curve::zip` (or just through explicit mapping of a similar form). It
would otherwise be kind of frustrating to stumble upon such a thing and
then realize that, e.g., automatic resampling just doesn't work, even
though there is a very "obvious" way to do it.
## Solution
Infer `StableInterpolate` on tuples of up to size 11. I can make that
number bigger, if desired. Unfortunately, I don't think that our
standard "fake variadics" tools actually work for this; the anonymous
field accessors of tuples are `:tt` for purposes of macro expansion,
which means that you can't simplify away the identifiers by doing
something clever like using recursion (which would work if they were
`:expr`). Maybe someone who knows some incredibly dark magic could chime
in with a better solution.
The expanded impls look like this:
```rust
impl<
T0: StableInterpolate,
T1: StableInterpolate,
T2: StableInterpolate,
T3: StableInterpolate,
T4: StableInterpolate,
> StableInterpolate for (T0, T1, T2, T3, T4)
{
fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
(
<T0 as StableInterpolate>::interpolate_stable(&self.0, &other.0, t),
<T1 as StableInterpolate>::interpolate_stable(&self.1, &other.1, t),
<T2 as StableInterpolate>::interpolate_stable(&self.2, &other.2, t),
<T3 as StableInterpolate>::interpolate_stable(&self.3, &other.3, t),
<T4 as StableInterpolate>::interpolate_stable(&self.4, &other.4, t),
)
}
}
```
## Testing
Expanded macros; it compiles.
## Future
Make a version of the fake variadics workflow that supports this kind of
thing.
# Objective
Closes#15799.
Many rendering people and maintainers are in favor of reverting default
mesh materials added in #15524, especially as the migration to required
component is already large and heavily breaking.
## Solution
Revert default mesh materials, and adjust docs accordingly.
- Remove `extract_default_materials`
- Remove `clear_material_instances`, and move the logic back into
`extract_mesh_materials`
- Remove `HasMaterial2d` and `HasMaterial3d`
- Change default material handles back to pink instead of white
- 2D uses `Color::srgb(1.0, 0.0, 1.0)`, while 3D uses `Color::srgb(1.0,
0.0, 0.5)`. Not sure if this is intended.
There is now no indication at all about missing materials for `Mesh2d`
and `Mesh3d`. Having a mesh without a material renders nothing.
## Testing
I ran `2d_shapes`, `mesh2d_manual`, and `3d_shapes`, with and without
mesh material components.
# Objective
Fixes#15730.
## Solution
As part of #15586, we made a constant to store all the supported image
formats. However since the `ImageFormat` does actually include Hdr and
OpenExr, it also included the `"hdr"` and `"exr"` file extensions. These
are supported by separate loaders though: `HdrTextureLoader` and
`ExrTextureLoader`. This led to a warning about duplicate asset loaders.
Therefore, instead of having the constant for `ImageFormat`, I made the
constant just for `ImageLoader`. This lets us correctly remove `"hdr"`
and `"exr"` from the image formats supported by `ImageLoader`, returning
us to having a single asset loader for every image format.
Note: we could have just removed `hdr` and `exr` from
`ImageFormat::SUPPORTED_FILE_EXTENSIONS`, but this would be very
confusing. Then the list of `ImageFormat`s would not match the list of
supported formats!
## Testing
- I ran the `sprite` example and got no warning! I also replaced the
sprite in that example with an HDR file and everything worked as
expected.
See #15924 for more details
close#15924
from the issue, this code panic:
```rust
use bevy::time::Stopwatch;
use std::time::Duration;
fn main() {
let second = Duration::from_secs(1);
let mut stopwatch = Stopwatch::new();
// lot of time has passed... or a timer with Duration::MAX that was artificially set has "finished":
// timer.set_elapsed(timer.remaining());
stopwatch.set_elapsed(Duration::MAX);
// panic
stopwatch.tick(second);
let mut stopwatch = Stopwatch::new();
stopwatch.set_elapsed(Duration::MAX - second);
// this doesnt panic as its still one off the max
stopwatch.tick(second);
// this panic
stopwatch.tick(second);
}
```
with this PR changes, the code now doesn't panic.
have a good day !
This is 3 of 5 iterative PR's that affect bevy_ui/layout
- [x] Blocked by https://github.com/bevyengine/bevy/pull/12801
- [x] Blocked by https://github.com/bevyengine/bevy/pull/12802
---
# Objective
- Add tests to `UiSurface`
- Add missing asserts in `_assert_send_sync_ui_surface_impl_safe`
- Add missing Debug field print for `camera_entity_to_taffy`
## Solution
- Adds tests to `UiSurface`
- Adds missing asserts in `_assert_send_sync_ui_surface_impl_safe`
- Adds missing impl Debug field print for `camera_entity_to_taffy`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Fixes#15897
## Solution
- Despawn light view entities when they go unused or when the
corresponding view is not alive.
## Testing
- `scene_viewer` example no longer prints "The preprocessing index
buffer wasn't present" warning
- modified an example to try toggling shadows for all kinds of light:
https://gist.github.com/akimakinai/ddb0357191f5052b654370699d2314cf
# Objective
Ensure that components that are conditionally extracted do not linger in
the render world when not extracted from the main world.
## Solution
If the `ExtractComponent` returns `None`, we'll remove the render world
component. I think this is the most sensible behavior here. In the
future if there really is a use case for keeping the previous render
component around, we could add a `Option<Self::Out>` parameter for the
previous render component to the method, or something similar. I think
that this follows the principle of least surprise here relative to what
`None` would suggest and the way that render nodes are typically
written. The alternative would be to add an `enabled` field to pretty
much every camera settings component, or duplicate the extraction
condition as #15856 does.
## Testing
`transmission` no longer crashes.
## Migration Guide
Components that implement `ExtractComponent` and return `None` will
cause the extracted component to be removed from the render world.
# Objective
Currently, is is very painful to wait for an asset to load from the
context of an `async` task. While bevy's `AssetServer` is asynchronous
at its core, the public API is mainly focused on being used from
synchronous contexts such as bevy systems. Currently, the best way of
waiting for an asset handle to finish loading is to have a system that
runs every frame, and either listens for `AssetEvents` or manually polls
the asset server. While this is an acceptable interface for bevy
systems, it is extremely awkward to do this in a way that integrates
well with the `async` task system. At my work we had to create our own
(inefficient) abstraction that encapsulated the boilerplate of checking
an asset's load status and waking up a task when it's done.
## Solution
Add the method `AssetServer::wait_for_asset`, which returns a future
that suspends until the asset associated with a given `Handle` either
finishes loading or fails to load.
## Testing
- CI
## Notes
This is an adoption of #14431, the above description is directly from
that original PR.
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
Co-authored-by: andriyDev <andriydzikh@gmail.com>
# Objective
Improve the average user's ability to understand what the heck is going
on with the Curve API.
## Solution
I wrote some docs. I doubt these are perfect; I'm probably far too close
to this for that to be the case. :)
# Objective
Cleanup naming and docs, add missing migration guide after #15591
All text root nodes now use `Text` (UI) / `Text2d`.
All text readers/writers use `Text<Type>Reader`/`Text<Type>Writer`
convention.
---
## Migration Guide
Doubles as #15591 migration guide.
Text bundles (`TextBundle` and `Text2dBundle`) were removed in favor of
`Text` and `Text2d`.
Shared configuration fields were replaced with `TextLayout`, `TextFont`
and `TextColor` components.
Just `TextBundle`'s additional field turned into `TextNodeFlags`
component,
while `Text2dBundle`'s additional fields turned into `TextBounds` and
`Anchor` components.
Text sections were removed in favor of hierarchy-based approach.
For root text entities with `Text` or `Text2d` components, child
entities with `TextSpan` will act as additional text sections.
To still access text spans by index, use the new `TextUiReader`,
`Text2dReader` and `TextUiWriter`, `Text2dWriter` system parameters.
# Objective
This is a follow-up to #15650. While the core `Image` stuff moved from
`bevy_render` to `bevy_image`, the `ImageLoader` and the
`CompressedImageSaver` remained in `bevy_render`.
## Solution
I moved `ImageLoader` and `CompressedImageSaver` to `bevy_image` and
re-exported everything out from `bevy_render`. The second step isn't
strictly necessary, but `bevy_render` is already doing this for all the
other `bevy_image` types, so I kept it the same for consistency.
Unfortunately I had to give `ImageLoader` a constructor so I can keep
the `RenderDevice` stuff in `bevy_render`.
## Testing
It compiles!
## Migration Guide
- `ImageLoader` can no longer be initialized directly through
`init_asset_loader`. Now you must use
`app.register_asset_loader(ImageLoader::new(supported_compressed_formats))`
(check out the implementation of `bevy_render::ImagePlugin`). This only
affects you if you are initializing the loader manually and does not
affect users of `bevy_render::ImagePlugin`.
## Followup work
- We should be able to move most of the `ImagePlugin` to `bevy_image`.
This would likely require an `ImagePlugin` and a `RenderImagePlugin` or
something though.
# Objective
- Closes#14774
## Solution
Added:
```rust
impl<'w, E, B: Bundle> Trigger<'w, E, B> {
pub fn components(&self) -> &[ComponentId];
}
```
I went with storing it in the trigger as a `SmallVec<[Component; 1]>`
because a singular target component will be the most common case, and it
remains the same size as `Vec<ComponentId>`.
## Testing
Added a test.
# Objective
Change UI clipping to respect borders and padding.
Fixes#15335
## Solution
Based on #15163
1. Add a `padding` field to `Node`.
2. In `ui_layout_size` copy the padding values from taffy to
`Node::padding`.
4. Determine the node's content box (The innermost part of the node
excluding the padding and border).
5. In `update_clipping` perform the clipping intersection with the
node's content box.
## Notes
* `Rect` probably needs some helper methods for working with insets but
because `Rect` and `BorderRect` are in different crates it's awkward to
add them. Left for a follow up.
* We could have another `Overflow` variant (probably called
`Overflow::Hidden`) to that clips inside of the border box instead of
the content box. Left it out here as I'm not certain about the naming or
behaviour though. If this PR is adopted, it would be trivial to add a
`Hidden` variant in a follow up.
* Depending on UI scaling there are sometimes gaps in the layout:
<img width="532" alt="rounding-bug"
src="https://github.com/user-attachments/assets/cc29aa0d-44fe-403f-8f0e-cd28a8b1d1b3">
This is caused by existing bugs in `ui_layout_system`'s coordinates
rounding and not anything to do with the changes in this PR.
## Testing
This PR also changes the `overflow` example to display borders on the
overflow nodes so you can see how this works:
#### main (The image is clipped at the edges of the node, overwriting
the border).
<img width="722" alt="main_overflow"
src="https://github.com/user-attachments/assets/eb316cd0-fff8-46ee-b481-e0cd6bab3f5c">
#### this PR (The image is clipped at the edges of the node's border).
<img width="711" alt="content-box-clip"
src="https://github.com/user-attachments/assets/fb302e56-9302-47b9-9a29-ec3e15fe9a9f">
## Migration Guide
Migration guide is on #15561
---------
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
# Objective
Another clippy-lint fix: the goal is so that `ci lints` actually
displays the problems that a contributor caused, and not a bunch of
existing stuff in the repo. (when run on nightly)
## Solution
This fixes all but the `clippy::needless_lifetimes` lint, which will
result in substantially more fixes and be in other PR(s). I also
explicitly allow `non_local_definitions` since it is [not working
correctly, but will be
fixed](https://github.com/rust-lang/rust/issues/131643).
A few things were manually fixed: for example, some places had an
explicitly defined `div_ceil` function that was used, which is no longer
needed since this function is stable on unsigned integers. Also, empty
lines in doc comments were handled individually.
## Testing
I ran `cargo clippy --workspace --all-targets --all-features --fix
--allow-staged` with the `clippy::needless_lifetimes` lint marked as
`allow` in `Cargo.toml` to avoid fixing that too. It now passes with all
but the listed lint.
# Objective
- Android doesn't receive lifecycle event `Suspended` before suspension
## Solution
- Fix update triggering just after state change on android
## Testing
- Tested on the android emulator
# Objective
The type `AssetLoadError` has `PartialEq` and `Eq` impls, which is
problematic due to the fact that the `AssetLoaderError` and
`AddAsyncError` variants lie in their impls: they will return `true` for
any `Box<dyn Error>` with the same `TypeId`, even if the actual value is
different. This can lead to subtle bugs if a user relies on the equality
comparison to ensure that two values are equal.
The same is true for `DependencyLoadState`,
`RecursiveDependencyLoadState`.
More generally, it is an anti-pattern for large error types involving
dynamic dispatch, such as `AssetLoadError`, to have equality
comparisons. Directly comparing two errors for equality is usually not
desired -- if some logic needs to branch based on the value of an error,
it is usually more correct to check for specific variants and inspect
their fields.
As far as I can tell, the only reason these errors have equality
comparisons is because the `LoadState` enum wraps `AssetLoadError` for
its `Failed` variant. This equality comparison is only used to check for
`== LoadState::Loaded`, which we can easily replace with an `is_loaded`
method.
## Solution
Remove the `{Partial}Eq` impls from `LoadState`, which also allows us to
remove it from the error types.
## Migration Guide
The types `bevy_asset::AssetLoadError` and `bevy_asset::LoadState` no
longer support equality comparisons. If you need to check for an asset's
load state, consider checking for a specific variant using
`LoadState::is_loaded` or the `matches!` macro. Similarly, consider
using the `matches!` macro to check for specific variants of the
`AssetLoadError` type if you need to inspect the value of an asset load
error in your code.
`DependencyLoadState` and `RecursiveDependencyLoadState` are not
released yet, so no migration needed,
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
# Objective
#15320 is a particularly painful breaking change, and the new
`RenderEntity` in particular is very noisy, with a lot of `let entity =
entity.id()` spam.
## Solution
Implement `WorldQuery`, `QueryData` and `ReadOnlyQueryData` for
`RenderEntity` and `WorldEntity`.
These work the same as the `Entity` impls from a user-facing
perspective: they simply return an owned (copied) `Entity` identifier.
This dramatically reduces noise and eases migration.
Under the hood, these impls defer to the implementations for `&T` for
everything other than the "call .id() for the user" bit, as they involve
read-only access to component data. Doing it this way (as opposed to
implementing a custom fetch, as tried in the first commit) dramatically
reduces the maintenance risk of complex unsafe code outside of
`bevy_ecs`.
To make this easier (and encourage users to do this themselves!), I've
made `ReadFetch` and `WriteFetch` slightly more public: they're no
longer `doc(hidden)`. This is a good change, since trying to vendor the
logic is much worse than just deferring to the existing tested impls.
## Testing
I've run a handful of rendering examples (breakout, alien_cake_addict,
auto_exposure, fog_volumes, box_shadow) and nothing broke.
## Follow-up
We should lint for the uses of `&RenderEntity` and `&MainEntity` in
queries: this is just less nice for no reason.
---------
Co-authored-by: Trashtalk217 <trashtalk217@gmail.com>
# Objective
- closes#15866
## Solution
- Simply migrate where possible.
## Testing
- Expect that CI will do most of the work. Examples is another way of
testing this, as most of the work is in that area.
---
## Notes
For now, this PR doesn't migrate `QueryState::single` and friends as for
now, this look like another issue. So for example, QueryBuilders that
used single or `World::query` that used single wasn't migrated. If there
is a easy way to migrate those, please let me know.
Most of the uses of `Query::single` were removed, the only other uses
that I found was related to tests of said methods, so will probably be
removed when we remove `Query::single`.
# Objective
`insert_or_spawn_batch` exists, but a version for just inserting doesn't
- Closes#2693
- Closes#8384
- Adopts/supersedes #8600
## Solution
Add `insert_batch`, along with the most common `insert` variations:
- `World::insert_batch`
- `World::insert_batch_if_new`
- `World::try_insert_batch`
- `World::try_insert_batch_if_new`
- `Commands::insert_batch`
- `Commands::insert_batch_if_new`
- `Commands::try_insert_batch`
- `Commands::try_insert_batch_if_new`
## Testing
Added tests, and added a benchmark for `insert_batch`.
Performance is slightly better than `insert_or_spawn_batch` when only
inserting:
![Code_HPnUN0QeWe](https://github.com/user-attachments/assets/53091e4f-6518-43f4-a63f-ae57d5470c66)
<details>
<summary>old benchmark</summary>
This was before reworking it to remove the `UnsafeWorldCell`:
![Code_QhXJb8sjlJ](https://github.com/user-attachments/assets/1061e2a7-a521-48e1-a799-1b6b8d1c0b93)
</details>
---
## Showcase
Usage is the same as `insert_or_spawn_batch`:
```
use bevy_ecs::{entity::Entity, world::World, component::Component};
#[derive(Component)]
struct A(&'static str);
#[derive(Component, PartialEq, Debug)]
struct B(f32);
let mut world = World::new();
let entity_a = world.spawn_empty().id();
let entity_b = world.spawn_empty().id();
world.insert_batch([
(entity_a, (A("a"), B(0.0))),
(entity_b, (A("b"), B(1.0))),
]);
assert_eq!(world.get::<B>(entity_a), Some(&B(0.0)));
```
# Objective
- Required components replace bundles, but `SpatialBundle` is yet to be
deprecated
## Solution
- Deprecate `SpatialBundle`
- Insert `Transform` and `Visibility` instead in examples using it
- In `spawn` or `insert` inserting a default `Transform` or `Visibility`
with component already requiring either, remove those components from
the tuple
## Testing
- Did you test these changes? If so, how?
Yes, I ran the examples I changed and tests
- Are there any parts that need more testing?
The `gamepad_viewer` and and `custom_shader_instancing` examples don't
work as intended due to entirely unrelated code, didn't check main.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Run examples, or just check that all spawned values are identical
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Linux, wayland trough x11 (cause that's the default feature)
---
## Migration Guide
`SpatialBundle` is now deprecated, insert `Transform` and `Visibility`
instead which will automatically insert all other components that were
in the bundle. If you do not specify these values and any other
components in your `spawn`/`insert` call already requires either of
these components you can leave that one out.
before:
```rust
commands.spawn(SpatialBundle::default());
```
after:
```rust
commands.spawn((Transform::default(), Visibility::default());
```
# Objective
Fixes#15515
## Solution
I went for the simplest solution because "format" in
`shader_format_spirv` didn't sound directly related.
## Testing
The command `cargo b -p bevy --no-default-features -F
spirv_shader_passthrough,x11` failed before, but works now.
# Objective
With the warning removed in
https://github.com/bevyengine/bevy/pull/15736, the rules for the UI tree
changes.
We no longer need to traverse non `Node`/`GhostNode` entities.
## Solution
- Added a filter `Or<(With<Node>, With<GhostNode>)>` to the child
traversal query so we don't unnecessarily traverse nodes that are not
part of the UI tree (like text nodes).
- Also moved the warning for NoUI->UI entities so it is actually
triggered (see comments)
## Testing
- Ran unit tests (still passing)
- Ran the ghost_nodes and ui examples, still works and looks fine 👍
- Tested the warning by spawning a Node under an empty entity.
---
---------
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
# Objective
Closes#15545.
`bevy_picking` supports UI and sprite picking, but not mesh picking.
Being able to pick meshes would be extremely useful for various games,
tools, and our own examples, as well as scene editors and inspectors.
So, we need a mesh picking backend!
Luckily,
[`bevy_mod_picking`](https://github.com/aevyrie/bevy_mod_picking) (which
`bevy_picking` is based on) by @aevyrie already has a [backend for
it](74f0c3c0fb/backends/bevy_picking_raycast/src/lib.rs)
using [`bevy_mod_raycast`](https://github.com/aevyrie/bevy_mod_raycast).
As a side product of adding mesh picking, we also get support for
performing ray casts on meshes!
## Solution
Upstream a large chunk of the immediate-mode ray casting functionality
from `bevy_mod_raycast`, and add a mesh picking backend based on
`bevy_mod_picking`. Huge thanks to @aevyrie who did all the hard work on
these incredible crates!
All meshes are pickable by default. Picking can be disabled for
individual entities by adding `PickingBehavior::IGNORE`, like normal.
Or, if you want mesh picking to be entirely opt-in, you can set
`MeshPickingBackendSettings::require_markers` to `true` and add a
`RayCastPickable` component to the desired camera and target entities.
You can also use the new `MeshRayCast` system parameter to cast rays
into the world manually:
```rust
fn ray_cast_system(mut ray_cast: MeshRayCast, foo_query: Query<(), With<Foo>>) {
let ray = Ray3d::new(Vec3::ZERO, Dir3::X);
// Only ray cast against entities with the `Foo` component.
let filter = |entity| foo_query.contains(entity);
// Never early-exit. Note that you can change behavior per-entity.
let early_exit_test = |_entity| false;
// Ignore the visibility of entities. This allows ray casting hidden entities.
let visibility = RayCastVisibility::Any;
let settings = RayCastSettings::default()
.with_filter(&filter)
.with_early_exit_test(&early_exit_test)
.with_visibility(visibility);
// Cast the ray with the settings, returning a list of intersections.
let hits = ray_cast.cast_ray(ray, &settings);
}
```
This is largely a direct port, but I did make several changes to match
our APIs better, remove things we don't need or that I think are
unnecessary, and do some general improvements to code quality and
documentation.
### Changes Relative to `bevy_mod_raycast` and `bevy_mod_picking`
- Every `Raycast` and "raycast" has been renamed to `RayCast` and "ray
cast" (similar reasoning as the "Naming" section in #15724)
- `Raycast` system param has been renamed to `MeshRayCast` to avoid
naming conflicts and to be explicit that it is not for colliders
- `RaycastBackend` has been renamed to `MeshPickingBackend`
- `RayCastVisibility` variants are now `Any`, `Visible`, and
`VisibleInView` instead of `Ignore`, `MustBeVisible`, and
`MustBeVisibleAndInView`
- `NoBackfaceCulling` has been renamed to `RayCastBackfaces`, to avoid
implying that it affects the rendering of backfaces for meshes (it
doesn't)
- `SimplifiedMesh` and `RayCastBackfaces` live near other ray casting
API types, not in their own 10 LoC module
- All intersection logic and types are in the same `intersections`
module, not split across several modules
- Some intersection types have been renamed to be clearer and more
consistent
- `IntersectionData` -> `RayMeshHit`
- `RayHit` -> `RayTriangleHit`
- General documentation and code quality improvements
### Removed / Not Ported
- Removed unused ray helpers and types, like `PrimitiveIntersection`
- Removed getters on intersection types, and made their properties
public
- There is no `2d` feature, and `Raycast::mesh_query` and
`Raycast::mesh2d_query` have been merged into `MeshRayCast::mesh_query`,
which handles both 2D and 3D
- I assume this existed previously because `Mesh2dHandle` used to be in
`bevy_sprite`. Now both the 2D and 3D mesh are in `bevy_render`.
- There is no `debug` feature or ray debug rendering
- There is no deferred API (`RaycastSource`)
- There is no `CursorRayPlugin` (the picking backend handles this)
### Note for Reviewers
In case it's helpful, the [first
commit](281638ef10)
here is essentially a one-to-one port. The rest of the commits are
primarily refactoring and cleaning things up in the ways listed earlier,
as well as changes to the module structure.
It may also be useful to compare the original [picking
backend](74f0c3c0fb/backends/bevy_picking_raycast/src/lib.rs)
and [`bevy_mod_raycast`](https://github.com/aevyrie/bevy_mod_raycast) to
this PR. Feel free to mention if there are any changes that I should
revert or something I should not include in this PR.
## Testing
I tested mesh picking and relevant components in some examples, for both
2D and 3D meshes, and added a new `mesh_picking` example. I also
~~stole~~ ported over the [ray-mesh intersection
benchmark](dbc5ef32fe/benches/ray_mesh_intersection.rs)
from `bevy_mod_raycast`.
---
## Showcase
Below is a version of the `2d_shapes` example modified to demonstrate 2D
mesh picking. This is not included in this PR.
https://github.com/user-attachments/assets/7742528c-8630-4c00-bacd-81576ac432bf
And below is the new `mesh_picking` example:
https://github.com/user-attachments/assets/b65c7a5a-fa3a-4c2d-8bbd-e7a2c772986e
There is also a really cool new `mesh_ray_cast` example ported over from
`bevy_mod_raycast`:
https://github.com/user-attachments/assets/3c5eb6c0-bd94-4fb0-bec6-8a85668a06c9
---------
Co-authored-by: Aevyrie <aevyrie@gmail.com>
Co-authored-by: Trent <2771466+tbillington@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
Currently text is recomputed unnecessarily on any changes to its color,
which is extremely expensive.
## Solution
Split up `TextStyle` into two separate components `TextFont` and
`TextColor`.
## Testing
I added this system to `many_buttons`:
```rust
fn set_text_colors_changed(mut colors: Query<&mut TextColor>) {
for mut text_color in colors.iter_mut() {
text_color.set_changed();
}
}
```
reports ~4fps on main, ~50fps with this PR.
## Migration Guide
`TextStyle` has been renamed to `TextFont` and its `color` field has
been moved to a separate component named `TextColor` which newtypes
`Color`.
# Objective
The previous `PhantomData` instances were written somewhat lazily, so
they were just things like `PhantomData<T>` for curves with an output
type of `T`. This looks innocuous, but it unnecessarily constrains
`Send/Sync` inference based on `T`. See
[here](https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns).
## Solution
Switch to `PhantomData` of the form `PhantomData<fn() -> T>` for most of
these adaptors. Since they only have a functional relationship to `T`
(i.e. it shows up in the return type of trait methods), this is more
accurate.
## Testing
Tested by compiling Bevy.
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
MacOS has some nice options for controlling the window and titlebar to
make the content appear much more "immersively" in the window. This PR
exposes options for controlling this.
## Solution
Adds new fields to `Window` to control these, with doc comments to
explain what they do and that they're MacOS only.
## Testing
Tested on a MacOS machine (not my own, I don't have one). That's where
the below screenshots were taken.
---
## Showcase
On MacOS, you now have more options for configuring the window titlebar.
You can, for example, make the title bar transparent and only show the
window controls. This provides a more "immersive" experience for your
rendered content.
Before, only this was possible:
<img width="1392" alt="image"
src="https://github.com/user-attachments/assets/abf03da2-d247-4202-a7e7-731c45d80d54">
Now, you can create windows like this:
<img width="1392" alt="image2"
src="https://github.com/user-attachments/assets/3239d0e3-4708-4798-8755-188541e14f93">
This uses the following `bevy_window::Window` settings:
```rs
fullsize_content_view: true,
titlebar_transparent: true,
titlebar_show_title: false,
```
## Migration Guide
`bevy_window::Window` now has extra fields for configuring MacOS window
settings:
```rs
pub movable_by_window_background: bool,
pub fullsize_content_view: bool,
pub has_shadow: bool,
pub titlebar_shown: bool,
pub titlebar_transparent: bool,
pub titlebar_show_title: bool,
pub titlebar_show_buttons: bool,
```
Using `Window::default` keeps the same behaviour as before.
# Objective
Animation docs could use some clarification regarding:
- how exactly curves are evaluated
- how additive blend nodes actually work
## Solution
Add some documentation that explains how curve domains are used and how
additive blend nodes treat their children.
## Commentary
The way additive blend nodes work right now is a little bit weird, since
their first child's weight is ignored. Arguably this makes sense, since
additive animations are authored differently from ordinary animations,
but it also feels a bit strange. We could make the first node's weight
actually be applied, and the present behavior would be recovered when
the weight is set to 1.
The main disadvantage of how things are set up now is that combining a
bunch of additive animations without a base pose is pretty awkward (e.g.
to add them onto a base pose later in the graph). If we changed it, the
main downside would be that reusing the same animation on different
parts of the graph is harder; on the other hand, the weights can be
locally reassigned by using blend nodes with no other children, which
rectifies this shortfall.
# Objective
On mobile devices, it's best to use the OS's native logging due to the
difficulty of accessing the console. This is already done for Android.
This is an updated version of
https://github.com/bevyengine/bevy/pull/4462.
## Solution
This PR uses Absolucy's
[tracing-oslog](https://github.com/Absolucy/tracing-oslog) ([ZLib
license](https://github.com/Absolucy/tracing-oslog/blob/main/LICENSE.md))
for iOS in order to use Apple's `os_log`.
## Testing
I ran `examples/mobile` with the logging from `examples/app/logs.rs` on
an iOS device, I then checked the logs could be filtered in the MacOS
Console.app.
## Changelog
- Change bevy_log to use Apple's os_log on iOS.
## Questions for Reviewers
It's worth noting that the dependency this adds hasn't had bug fixes
released in a few years, so we may want to consider one or more of:
1. a feature flag to opt-in, and it would also allow `os_log` on MacOS
2. merge as-is and have some (minor?) upstream bugs
3. hold off on this PR until a suitable alternative dependency arises
4. maintain our own implementation
## Future work
In a follow-up PR it might be good to make the `subsystem` field have a
better default value, like [this
one](https://github.com/bevyengine/bevy/blob/main/examples/mobile/bevy_mobile_example.xcodeproj/project.pbxproj#L363).
That value can be retrieved programmatically if we bind another system
API (For posterity in Swift this is `Bundle.main.bundleIdentifier`, but
the C/ObjC equivalent is likely easier to bind). This would almost
always be the correct value, while the current default is unlikely to
ever be correct.
---------
Co-authored-by: Dusty DeWeese <dustin.deweese@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
Oftentimes, users will store an entity on a component or resource. To
make this component/resource `Default`-able, they might initialize it
with `Entity::PLACEHOLDER`. This is sometimes done to avoid the need for
an `Option<Entity>`, especially if it complicates other logic.
For example, it's used in this `Selection` resource to denote "no
selection":
```rust
#[derive(Resource, Debug)]
struct Selection(Entity);
impl Default for Selection {
fn default() -> Self {
Self(Entity::PLACEHOLDER)
}
}
```
The problem is that if we try to `Debug` the current `Selection`, we get
back: `4294967295v1#8589934591`. It's not immediately obvious whether or
not the entity is an actual entity or the placeholder.
Now while it doesn't take long to realize that this is in fact just the
value of `Entity::PLACEHOLDER`, it would be a lot clearer if this was
made explicit, especially for these particular use cases.
## Solution
This PR makes the `Debug` and `Display` impls for `Entity` return
`PLACEHOLDER` for the `Entity::PLACEHOLDER` constant.
~~Feel free to bikeshed the actual value returned here. I think
`PLACEHOLDER` on its own could work too.~~ Swapped to `PLACEHOLDER` from
`Entity::PLACEHOLDER`.
## Testing
You can test locally by running:
```
cargo test --package bevy_ecs
```
---
## Migration Guide
The `Debug` and `Display` impls for `Entity` now return `PLACEHOLDER`
for the `Entity::PLACEHOLDER` constant. If you had any code relying on
these values, you may need to account for this change.
# Objective
- Immediate mode gizmos don't have a main world entity but the phase
items require `MainEntity` since #15756
## Solution
- Add a dummy `MainEntity` component.
## Testing
Both the `3d_gizmos` and `2d_gizmos` examples show gizmos again
# Objective
The other `Curve -> AnimationCurve` wrappers allow public access to the
inner curve, so this one should as well.
## Solution
Made the field public. Instances will still need to be constructed using
the (more ergonomic) `from_curve` method, which infers the phantom type
for the user.
# Objective
- We don't have to `collect` and `sort` invisible sprites in
`sprite_picking` system.
## Solution
- Filter by `ViewVisibility::get()` earlier
## Testing
- `sprite_picking` example still works.
# Objective
In the Render World, there are a number of collections that are derived
from Main World entities and are used to drive rendering. The most
notable are:
- `VisibleEntities`, which is generated in the `check_visibility` system
and contains visible entities for a view.
- `ExtractedInstances`, which maps entity ids to asset ids.
In the old model, these collections were trivially kept in sync -- any
extracted phase item could look itself up because the render entity id
was guaranteed to always match the corresponding main world id.
After #15320, this became much more complicated, and was leading to a
number of subtle bugs in the Render World. The main rendering systems,
i.e. `queue_material_meshes` and `queue_material2d_meshes`, follow a
similar pattern:
```rust
for visible_entity in visible_entities.iter::<With<Mesh2d>>() {
let Some(mesh_instance) = render_mesh_instances.get_mut(visible_entity) else {
continue;
};
// Look some more stuff up and specialize the pipeline...
let bin_key = Opaque2dBinKey {
pipeline: pipeline_id,
draw_function: draw_opaque_2d,
asset_id: mesh_instance.mesh_asset_id.into(),
material_bind_group_id: material_2d.get_bind_group_id().0,
};
opaque_phase.add(
bin_key,
*visible_entity,
BinnedRenderPhaseType::mesh(mesh_instance.automatic_batching),
);
}
```
In this case, `visible_entities` and `render_mesh_instances` are both
collections that are created and keyed by Main World entity ids, and so
this lookup happens to work by coincidence. However, there is a major
unintentional bug here: namely, because `visible_entities` is a
collection of Main World ids, the phase item being queued is created
with a Main World id rather than its correct Render World id.
This happens to not break mesh rendering because the render commands
used for drawing meshes do not access the `ItemQuery` parameter, but
demonstrates the confusion that is now possible: our UI phase items are
correctly being queued with Render World ids while our meshes aren't.
Additionally, this makes it very easy and error prone to use the wrong
entity id to look up things like assets. For example, if instead we
ignored visibility checks and queued our meshes via a query, we'd have
to be extra careful to use `&MainEntity` instead of the natural
`Entity`.
## Solution
Make all collections that are derived from Main World data use
`MainEntity` as their key, to ensure type safety and avoid accidentally
looking up data with the wrong entity id:
```rust
pub type MainEntityHashMap<V> = hashbrown::HashMap<MainEntity, V, EntityHash>;
```
Additionally, we make all `PhaseItem` be able to provide both their Main
and Render World ids, to allow render phase implementors maximum
flexibility as to what id should be used to look up data.
You can think of this like tracking at the type level whether something
in the Render World should use it's "primary key", i.e. entity id, or
needs to use a foreign key, i.e. `MainEntity`.
## Testing
##### TODO:
This will require extensive testing to make sure things didn't break!
Additionally, some extraction logic has become more complicated and
needs to be checked for regressions.
## Migration Guide
With the advent of the retained render world, collections that contain
references to `Entity` that are extracted into the render world have
been changed to contain `MainEntity` in order to prevent errors where a
render world entity id is used to look up an item by accident. Custom
rendering code may need to be changed to query for `&MainEntity` in
order to look up the correct item from such a collection. Additionally,
users who implement their own extraction logic for collections of main
world entity should strongly consider extracting into a different
collection that uses `MainEntity` as a key.
Additionally, render phases now require specifying both the `Entity` and
`MainEntity` for a given `PhaseItem`. Custom render phases should ensure
`MainEntity` is available when queuing a phase item.
# Objective
- Closes#15716
- Closes#15718
## Solution
- Replace `Handle<MeshletMesh>` with a new `MeshletMesh3d` component
- As expected there were some random things that needed fixing:
- A couple tests were storing handles just to prevent them from being
dropped I believe, which seems to have been unnecessary in some.
- The `SpriteBundle` still had a `Handle<Image>` field. I've removed
this.
- Tests in `bevy_sprite` incorrectly added a `Handle<Image>` field
outside of the `Sprite` component.
- A few examples were still inserting `Handle`s, switched those to their
corresponding wrappers.
- 2 examples that were still querying for `Handle<Image>` were changed
to query `Sprite`
## Testing
- I've verified that the changed example work now
## Migration Guide
`Handle` can no longer be used as a `Component`. All existing Bevy types
using this pattern have been wrapped in their own semantically
meaningful type. You should do the same for any custom `Handle`
components your project needs.
The `Handle<MeshletMesh>` component is now `MeshletMesh3d`.
The `WithMeshletMesh` type alias has been removed. Use
`With<MeshletMesh3d>` instead.
# Objective
If a `Resource` implements `FromWorld` or `Default`, it's nicer to be
able to write:
```rust
let foo = world.get_resource_or_init::<Foo>();
```
Rather than:
```rust
let foo = world.get_resource_or_insert_with(Foo::default);
```
The latter is also not possible if a type implements `FromWorld` only,
and not `Default`.
## Solution
Added:
```rust
impl World {
pub fn get_resource_or_init<R: Resource + FromWorld>(&mut self) -> Mut<'_, R>;
}
```
Turns out all current in-engine uses of `get_resource_or_insert_with`
are exactly the above, so they've also been replaced.
## Testing
- Added a doc-test.
- Also added a doc-test for `World::get_resource_or_insert_with`.
In order to create texture atlases from other systems (custom game
solutions) that are compatible with the ones generated by the bevy
builders, it would be nice to have the interface be fully public. This
field is pub(crate). Unless there's a good reason, can we promote this
to pub?
Alternatives:
- Don't do it.
**Ready for review. Examples migration progress: 100%.**
# Objective
- Implement https://github.com/bevyengine/bevy/discussions/15014
## Solution
This implements [cart's
proposal](https://github.com/bevyengine/bevy/discussions/15014#discussioncomment-10574459)
faithfully except for one change. I separated `TextSpan` from
`TextSpan2d` because `TextSpan` needs to require the `GhostNode`
component, which is a `bevy_ui` component only usable by UI.
Extra changes:
- Added `EntityCommands::commands_mut` that returns a mutable reference.
This is a blocker for extension methods that return something other than
`self`. Note that `sickle_ui`'s `UiBuilder::commands` returns a mutable
reference for this reason.
## Testing
- [x] Text examples all work.
---
## Showcase
TODO: showcase-worthy
## Migration Guide
TODO: very breaking
### Accessing text spans by index
Text sections are now text sections on different entities in a
hierarchy, Use the new `TextReader` and `TextWriter` system parameters
to access spans by index.
Before:
```rust
fn refresh_text(mut query: Query<&mut Text, With<TimeText>>, time: Res<Time>) {
let text = query.single_mut();
text.sections[1].value = format_time(time.elapsed());
}
```
After:
```rust
fn refresh_text(
query: Query<Entity, With<TimeText>>,
mut writer: UiTextWriter,
time: Res<Time>
) {
let entity = query.single();
*writer.text(entity, 1) = format_time(time.elapsed());
}
```
### Iterating text spans
Text spans are now entities in a hierarchy, so the new `UiTextReader`
and `UiTextWriter` system parameters provide ways to iterate that
hierarchy. The `UiTextReader::iter` method will give you a normal
iterator over spans, and `UiTextWriter::for_each` lets you visit each of
the spans.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Another step towards #15716
- Remove trait implementations that are dependent on `Handle<T>` being a
`Component`
## Solution
- Remove unused `ExtractComponent` trait implementation for `Handle<T>`
- Remove unused `ExtractInstance` trait implementation for `AssetId`
- Although the `ExtractInstance` trait wasn't used, the `AssetId`s were
being stored inside of `ExtractedInstances` which has an
`ExtractInstance` trait bound on its contents.
I've upgraded the `RenderMaterialInstances` type alias to be its own
resource, identical to `ExtractedInstances<AssetId<M>>` to get around
that with minimal breakage.
## Testing
Tested `many_cubes`, rendering did not explode
# Objective
A bunch of code is used only if you care about the `Curve` trait. Put it
behind a feature so it can be ignored if wanted.
## Solution
Added a default feature `curve` to `bevy_math` which feature-gates the
`curve` module and internal integrations.
## Testing
Tested compiling with the feature enabled and disabled.
# Objective
Continue migration of bevy APIs to required components, following
guidance of https://hackmd.io/@bevy/required_components/
## Solution
- Make `Sprite` require `Transform` and `Visibility` and
`SyncToRenderWorld`
- move image and texture atlas handles into `Sprite`
- deprecate `SpriteBundle`
- remove engine uses of `SpriteBundle`
## Testing
ran cargo tests on bevy_sprite and tested several sprite examples.
---
## Migration Guide
Replace all uses of `SpriteBundle` with `Sprite`. There are several new
convenience constructors: `Sprite::from_image`,
`Sprite::from_atlas_image`, `Sprite::from_color`.
WARNING: use of `Handle<Image>` and `TextureAtlas` as components on
sprite entities will NO LONGER WORK. Use the fields on `Sprite` instead.
I would have removed the `Component` impls from `TextureAtlas` and
`Handle<Image>` except it is still used within ui. We should fix this
moving forward with the migration.
# Objective
- Closes#15752
Calling the functions `App::observe` and `World::observe` doesn't make
sense because you're not "observing" the `App` or `World`, you're adding
an observer that listens for an event that occurs *within* the `World`.
We should rename them to better fit this.
## Solution
Renames:
- `App::observe` -> `App::add_observer`
- `World::observe` -> `World::add_observer`
- `Commands::observe` -> `Commands::add_observer`
- `EntityWorldMut::observe_entity` -> `EntityWorldMut::observe`
(Note this isn't a breaking change as the original rename was introduced
earlier this cycle.)
## Testing
Reusing current tests.
# Objective
Fixes#15726
The extraction logic for components makes use of `FromReflect` to try
and ensure we have a concrete type for serialization. However, we did
not do the same for resources.
The reason we're seeing this for the glam types is that #15174 also made
a change to rely on the glam type's `Serialize` and `Deserialize` impls,
which I don't think should have been merged (I'll put up a PR addressing
this specifically soon).
## Solution
Use `FromReflect` on extracted resources.
## Testing
You can test locally by running:
```
cargo test --package bevy_scene
```
# Objective
Getting closer to the end! Another part of the required components
migration: reflection probes.
## Solution
As per the [proposal added by
Cart](https://hackmd.io/@bevy/required_components/%2FNmpIh0tGSiayGlswbfcEzw)
(Proposal 2), make `LightProbe` require `Transform` and `Visibility`,
and deprecate `ReflectionProbeBundle`.
Note that this proposal wasn't officially blessed yet, but it is the
only existing one that really works, so I implemented it here for
consideration.
## Testing
I ran the reflection probe example, and it appears to work.
---
## Migration Guide
`ReflectionProbeBundle` has been deprecated in favor of inserting the
`LightProbe` and `EnvironmentMapLight` components directly. Inserting
them will now automatically insert `Transform` and `Visibility`
components.
---------
Co-authored-by: Tim Blackbird <justthecooldude@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Fixes#15285
## Solution
`winit` sends resized to zero events when the window is minimized only
on Windows OS(rust-windowing/winit#2015).
This makes updating window viewport size to `(0, 0)` and panicking when
calculating aspect ratio.
~~So, just skip these kinds of events - resizing to (0, 0) when the
window is minimized - on Windows OS~~
Idially, the camera extraction excludes the cameras whose target size
width or height is zero here;
25bfa80e60/crates/bevy_render/src/camera/camera.rs (L1060-L1074)
but it seems that winit event loop sends resize events after extraction
and before post update schedule, so they might panics before the
extraction filters them out.
Alternatively, it might be possible to change event loop evaluating
order or defer them to the right schedule but I'm afraid that it might
cause some breaking changes, so just skip rendering logics for such
windows and they will be all filtered out by the extractions on the next
frame and thereafter.
## Testing
Running the example in the original issue and minimizing causes panic,
or just running `tests/window/minimising.rs` with `cargo run --example
minimising` panics without this PR and doesn't panics with this PR.
I think that we should run it in CI on Windows OS btw
# Objective
- Fixes (partially) #15701.
## Solution
- Use little-endian bytes over native-endian bytes where applicable.
## Testing
- Ran CI.
## Open Questions
- Should we config-gate these for big-endian targets? It looks like
there are [very few
targets](https://doc.rust-lang.org/nightly/rustc/platform-support.html)
that use big-endian.
# Objective
- Closes#15717
## Solution
- Wrap the handle in a new wrapper component: `AnimationGraphHandle`.
## Testing
Searched for all instances of `AnimationGraph` in the examples and
updated and tested those
## Migration Guide
`Handle<AnimationGraph>` is no longer a component. Instead, use the
`AnimationGraphHandle` component which contains a
`Handle<AnimationGraph>`.
# Objective
Fixes#15741
## Solution
- Copied the feature gates of a type to where the type is used.
## Testing
- `cargo check` works now using only the bevy_dev_tools feature
# Objective
- Size is currently hardcoded in the shader which means it will break if
a user uses anything higher than that.
## Solution
- Use a shader_def to define the size
## Testing
Tested with the OIT example
# Objective
The UI text rendering is really slow because it extracts each glyph as a
separate ui node even though all the glyphs in a text section have the
same texture, color and clipping rects.
## Solution
Store the glyphs in a seperate contiguous array, queue one transparent
ui item per text section which has indices into the glyph array.
## Testing
```cargo run --example many_glyphs --release```
Runs at about 22fps on main and 95fps with this PR on my computer.
I'll do some proper comparisons once I work out why tracy 11 is refusing to run.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
# Objective
Fixes#15560
Fixes (most of) #15570
Currently a lot of examples (and presumably some user code) depend on
toggling certain render features by adding/removing a single component
to an entity, e.g. `SpotLight` to toggle a light. Because of the
retained render world this no longer works: Extract will add any new
components, but when it is removed the entity persists unchanged in the
render world.
## Solution
Add `SyncComponentPlugin<C: Component>` that registers
`SyncToRenderWorld` as a required component for `C`, and adds a
component hook that will clear all components from the render world
entity when `C` is removed. We add this plugin to
`ExtractComponentPlugin` which fixes most instances of the problem. For
custom extraction logic we can manually add `SyncComponentPlugin` for
that component.
We also rename `WorldSyncPlugin` to `SyncWorldPlugin` so we start a
naming convention like all the `Extract` plugins.
In this PR I also fixed a bunch of breakage related to the retained
render world, stemming from old code that assumed that `Entity` would be
the same in both worlds.
I found that using the `RenderEntity` wrapper instead of `Entity` in
data structures when referring to render world entities makes intent
much clearer, so I propose we make this an official pattern.
## Testing
Run examples like
```
cargo run --features pbr_multi_layer_material_textures --example clearcoat
cargo run --example volumetric_fog
```
and see that they work, and that toggles work correctly. But really we
should test every single example, as we might not even have caught all
the breakage yet.
---
## Migration Guide
The retained render world notes should be updated to explain this edge
case and `SyncComponentPlugin`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Trashtalk217 <trashtalk217@gmail.com>
# Objective
- `interpolation` crates provides all the curves functions, but some of
them were wrong
- We have a partial solution where some functions comes from the
external crate, some from bevy_math
## Solution
- Move them all to bevy_math
- Remove the dependency on `interpolation`
## Testing
Playing the `easing_functions` example
![easing-functions](https://github.com/user-attachments/assets/88832f34-4bb3-4dc2-85af-7b9e4fa23e52)
# Objective
As discussed in #15591, this warning prevents us from storing leaf nodes
without a `Style` component. Because text sections (as distinct
entities) should not be laid out using `taffy`, this warning is
incorrect.
Users may also have other uses for doing this, and this should generally
increase flexibility without posing particularly serious correctness
concerns.
## Solution
- removed warning about non-UI children with UI parents
- improved the warning about UI parents with non-UI parents
- this warning should stay, for now, as it results in a genuine failure
to perform `taffy` layout
- that said, we should be clearer about the cause and potentially
harmful results of this!
## Testing
I inserted an empty entity into the hierarchy in the `button` example as
a leaf node, and it ran with no warnings.
# Objective
Simplify the API surrounding easing curves. Broaden the base of types
that support easing.
## Solution
There is now a single library function, `easing_curve`, which constructs
a unit-parametrized easing curve between two values based on an
`EaseFunction`:
```rust
/// Given a `start` and `end` value, create a curve parametrized over [the unit interval]
/// that connects them, using the given [ease function] to determine the form of the
/// curve in between.
///
/// [the unit interval]: Interval::UNIT
/// [ease function]: EaseFunction
pub fn easing_curve<T: Ease>(start: T, end: T, ease_fn: EaseFunction) -> EasingCurve<T> { //... }
```
As this shows, the type of the output curve is generic only in `T`. In
particular, as long as `T` is `Reflect` (and `FromReflect` etc. — i.e.,
a standard "well-behaved" reflectable type), `EasingCurve<T>` is also
`Reflect`, and there is no special field handling nonsense. Therefore,
`EasingCurve` is the kind of thing that would be able to be easily
changed in an editor. This is made possible by storing the actual
`EaseFunction` on `EasingCurve<T>` instead of indirecting through some
kind of function type (which generally leads to issues with reflection).
The types that can be eased are those that implement a trait `Ease`:
```rust
/// A type whose values can be eased between.
///
/// This requires the construction of an interpolation curve that actually extends
/// beyond the curve segment that connects two values, because an easing curve may
/// extrapolate before the starting value and after the ending value. This is
/// especially common in easing functions that mimic elastic or springlike behavior.
pub trait Ease: Sized {
/// Given `start` and `end` values, produce a curve with [unlimited domain]
/// that:
/// - takes a value equivalent to `start` at `t = 0`
/// - takes a value equivalent to `end` at `t = 1`
/// - has constant speed everywhere, including outside of `[0, 1]`
///
/// [unlimited domain]: Interval::EVERYWHERE
fn interpolating_curve_unbounded(start: &Self, end: &Self) -> impl Curve<Self>;
}
```
(I know, I know, yet *another* interpolation trait. See 'Future
direction'.)
The other existing easing functions from the previous version of this
module have also become new members of `EaseFunction`: `Linear`,
`Steps`, and `Elastic` (which maybe needs a different name). The latter
two are parametrized.
## Testing
Tested using the `easing_functions` example. I also axed the
`cubic_curve` example which was of questionable value and replaced it
with `eased_motion`, which uses this API in the context of animation:
https://github.com/user-attachments/assets/3c802992-6b9b-4b56-aeb1-a47501c29ce2
---
## Future direction
Morally speaking, `Ease` is incredibly similar to `StableInterpolate`.
Probably, we should just merge `StableInterpolate` into `Ease`, and then
make `SmoothNudge` an automatic extension trait of `Ease`. The reason I
didn't do that is that `StableInterpolate` is not implemented for
`VectorSpace` because of concerns about the `Color` types, and I wanted
to avoid controversy. I think that may be a good idea though.
As Alice mentioned before, we should also probably get rid of the
`interpolation` dependency.
The parametrized `Elastic` variant probably also needs some additional
work (e.g. renaming, in/out/in-out variants, etc.) if we want to keep
it.
# Objective
- Closes#15720
## Solution
Wrap the handle in a new wrapper component: `UiMaterialHandle`
It's not possible to match the naming convention of `MeshMaterial3d/2d`
here with the trait already being called `UiMaterial`
Should we consider renaming to `Material3d/2dHandle` and `Mesh3d/2d` to
`Mesh3d/2dHandle`?
- This shouldn't have any merge conflicts with #15591
## Testing
Tested the `ui_material` example
## Migration Guide
Let's defer the migration guide to the required component port. I just
want to yeet the `Component` impl on `Handle` in the meantime :)
# Objective
- Prepare for streaming by storing vertex data per-meshlet, rather than
per-mesh (this means duplicating vertices per-meshlet)
- Compress vertex data to reduce the cost of this
## Solution
The important parts are in from_mesh.rs, the changes to the Meshlet type
in asset.rs, and the changes in meshlet_bindings.wgsl. Everything else
is pretty secondary/boilerplate/straightforward changes.
- Positions are quantized in centimeters with a user-provided power of 2
factor (ideally auto-determined, but that's a TODO for the future),
encoded as an offset relative to the minimum value within the meshlet,
and then stored as a packed list of bits using the minimum number of
bits needed for each vertex position channel for that meshlet
- E.g. quantize positions (lossly, throws away precision that's not
needed leading to using less bits in the bitstream encoding)
- Get the min/max quantized value of each X/Y/Z channel of the quantized
positions within a meshlet
- Encode values relative to the min value of the meshlet. E.g. convert
from [min, max] to [0, max - min]
- The new max value in the meshlet is (max - min), which only takes N
bits, so we only need N bits to store each channel within the meshlet
(lossless)
- We can store the min value and that it takes N bits per channel in the
meshlet metadata, and reconstruct the position from the bitstream
- Normals are octahedral encoded and than snorm2x16 packed and stored as
a single u32.
- Would be better to implement the precise variant of octhedral encoding
for extra precision (no extra decode cost), but decided to keep it
simple for now and leave that as a followup
- Tried doing a quantizing and bitstream encoding scheme like I did for
positions, but struggled to get it smaller. Decided to go with this for
simplicity for now
- UVs are uncompressed and take a full 64bits per vertex which is
expensive
- In the future this should be improved
- Tangents, as of the previous PR, are not explicitly stored and are
instead derived from screen space gradients
- While I'm here, split up MeshletMeshSaverLoader into two separate
types
Other future changes include implementing a smaller encoding of triangle
data (3 u8 indices = 24 bits per triangle currently), and more
disk-oriented compression schemes.
References:
* "A Deep Dive into UE5's Nanite Virtualized Geometry"
https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf#page=128
(also available on youtube)
* "Towards Practical Meshlet Compression"
https://arxiv.org/pdf/2404.06359
* "Vertex quantization in Omniforce Game Engine"
https://daniilvinn.github.io/2024/05/04/omniforce-vertex-quantization.html
## Testing
- Did you test these changes? If so, how?
- Converted the stanford bunny, and rendered it with a debug material
showing normals, and confirmed that it's identical to what's on main.
EDIT: See additional testing in the comments below.
- Are there any parts that need more testing?
- Could use some more size comparisons on various meshes, and testing
different quantization factors. Not sure if 4 is a good default. EDIT:
See additional testing in the comments below.
- Also did not test runtime performance of the shaders. EDIT: See
additional testing in the comments below.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Use my unholy script, replacing the meshlet example
https://paste.rs/7xQHk.rs (must make MeshletMesh fields pub instead of
pub crate, must add lz4_flex as a dev-dependency) (must compile with
meshlet and meshlet_processor features, mesh must have only positions,
normals, and UVs, no vertex colors or tangents)
---
## Migration Guide
- TBD by JMS55 at the end of the release
# Objective
The `new` constructors for our ray types currently take a `Vec2`/`Vec3`
instead of a `Dir2`/`Dir3`. This is confusing and footgunny for several
reasons.
- Which one of these is the direction? You can't see it from the type.
```rust
let ray = Ray2d::new(Vec2::X, Vec2::X);
```
- Many engines allow unnormalized rays, and this can affect ray cast
results by scaling the time of impact. However, in Bevy, rays are
*always* normalized despite what the input argument in this case
implies, and ray cast results are *not* scaled.
```rust
// The true ray direction is still normalized, unlike what you'd expect.
let ray = Ray2d::new(Vec2::X, Vec2::new(5.0, 0.0, 0.0)));
```
These cases are what the direction types are intended for, and we should
use them as such.
## Solution
Use `Dir2`/`Dir3` in the constructors.
```rust
let ray = Ray2d::new(Vec2::X, Dir2::X);
```
We *could* also use `impl TryInto<DirN>`, which would allow both vectors
and direction types, and then panic if the input is not normalized. This
could be fine for ergonomics in some cases, but especially for rays, I
think it's better to take an explicit direction type here.
---
## Migration Guide
`Ray2d::new` and `Ray3d::new` now take a `Dir2` and `Dir3` instead of
`Vec2` and `Vec3` respectively for the ray direction.
# Objective
Expose the `winit` functions
[drag_window](https://docs.rs/winit/latest/winit/window/struct.Window.html#method.drag_window)
and
[resize_window](https://docs.rs/winit/latest/winit/window/struct.Window.html#method.drag_resize_window).
Which allows implementing move & resize for windows without decorations.
## Solution
Add the functions `start_drag_move` and `start_drag_resize` to
`bevy_window::Window`, which are then assigned to fields in
`InternalWindowState`, and propagated to `winit` in the
`changed_windows` system.
## Testing
I've tested that both functions works on x11 and wayland. Not sure if
someone needs to test on windows/mac?
---
## Showcase
[Screencast from 2024-10-06 11-49-58
(trimmed).webm](https://github.com/user-attachments/assets/1cdee7b1-22bd-41d3-8a0a-6872a6ebf62c)
(The flickering in the video is some issue with resizing without
decorations on x11)
<details>
<summary>Click to view showcase</summary>
Not the same code used in the video, but simple way to test moving a
window without decorations.
```rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
decorations: false,
..default()
}),
..default()
}))
.add_systems(Update, move_windows)
.run();
}
fn move_windows(mut windows: Query<&mut Window>, input: Res<ButtonInput<MouseButton>>) {
if input.pressed(MouseButton::Left) {
for mut window in windows.iter_mut() {
window.start_drag_move();
}
}
}
```
</details>
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
UI box shadow support
Adds a new component `BoxShadow`:
```rust
pub struct BoxShadow {
/// The shadow's color
pub color: Color,
/// Horizontal offset
pub x_offset: Val,
/// Vertical offset
pub y_offset: Val,
/// Horizontal difference in size from the occluding uninode
pub spread_radius: Val,
/// Blurriness of the shadow
pub blur_radius: Val,
}
```
To use `BoxShadow`, add the component to any Bevy UI node and a shadow
will be drawn beneath that node.
Also adds a resource `BoxShadowSamples` that can be used to adjust the
shadow quality.
#### Notes
* I'm not super happy with the field names. Maybe we need a `struct Size
{ width: Val, height: Val }` type or something.
* The shader isn't very optimised but I don't see that it's too
important for now as the number of shadows being rendered is not going
to be massive most of the time. I think it's more important to get the
API and geometry correct with this PR.
* I didn't implement an inset property, it's not essential and can
easily be added in a follow up.
* Shadows are only rendered for uinodes, not for images or text.
* Batching isn't supported, it would need out-of-the-scope-of-this-pr
changes to the way the UI handles z-ordering for it to be effective.
# Showcase
```cargo run --example box_shadow -- --samples 4```
<img width="391" alt="br" src="https://github.com/user-attachments/assets/4e8add96-dc93-46e0-9e35-d995eb0943ad">
```cargo run --example box_shadow -- --samples 10```
<img width="391" alt="s10"
src="https://github.com/user-attachments/assets/ecb384c9-4012-4cd6-9dea-5180904bf28e">
## Objective
Add a way to stream BRP requests when the data changes.
## Solution
#### BRP Side (reusable for other transports)
Add a new method handler type that returns a optional value. This
handler is run in update and if a value is returned it will be sent on
the message channel. Custom watching handlers can be added with
`RemotePlugin::with_watching_method`.
#### HTTP Side
If a request comes in with `+watch` in the method, it will respond with
`text/event-stream` rather than a single response.
## Testing
I tested with the podman HTTP client. This client has good support for
SSE's if you want to test it too.
## Parts I want some opinions on
- For separating watching methods I chose to add a `+watch` suffix to
the end kind of like `content-type` headers. A get would be
`bevy/get+watch`.
- Should watching methods send an initial response with everything or
only respond when a change happens? Currently the later is what happens.
## Future work
- The `bevy/query` method would also benefit from this but that
condition will be quite complex so I will leave that to later.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
Several of our APIs (namely gizmos and bounding) use isometries on
current Bevy main. This is nicer than separate properties in a lot of
cases, but users have still expressed usability concerns.
One problem is that in a lot of cases, you only care about e.g.
translation, so you end up with this:
```rust
gizmos.cross_2d(
Isometry2d::from_translation(Vec2::new(-160.0, 120.0)),
12.0,
FUCHSIA,
);
```
The isometry adds quite a lot of length and verbosity, and isn't really
that relevant since only the translation is important here.
It would be nice if you could use the translation directly, and only
supply an isometry if both translation and rotation are needed. This
would make the following possible:
```rust
gizmos.cross_2d(Vec2::new(-160.0, 120.0), 12.0, FUCHSIA);
```
removing a lot of verbosity.
## Solution
Implement `From<Vec2>` and `From<Rot2>` for `Isometry2d`, and
`From<Vec3>`, `From<Vec3A>`, and `From<Quat>` for `Isometry3d`. These
are lossless conversions that fit the semantics of `From`.
This makes the proposed API possible! The methods must now simply take
an `impl Into<IsometryNd>`, and this works:
```rust
gizmos.cross_2d(Vec2::new(-160.0, 120.0), 12.0, FUCHSIA);
```