# Objective
- Add a release note for the new zstd backend.
- Doing so, I realized it was really cumbersome to enable this feature
because we default-enable ruzstd AND make it take precedence if both are
enabled. We can improve ux a bit by making the optional feature take
precedence when both are enabled. This still doesnt remove the unneeded
dependency, but oh well.
Note: it would be nice to have a way to make zstd_c not do anything when
building wasm, but im not sure theres a way to do that, as it seems like
it would need negative features.
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Progress towards #19887.
## Solution
- For cases that don't need to conditionally add systems, we can just
replace FromWorld impls with systems and then add those systems to
`RenderStartup`.
## Testing
- I ran the `lightmaps`, `reflection_probes`, `deferred_rendering`,
`volumetric_fog`, and `wireframe` examples.
Notifications now include the source entity. This is useful for
callbacks that are responsible for more than one widget.
Part of #19236
This is an incremental change only: I have not altered the fundamental
nature of callbacks, as this is still in discussion. The only change
here is to include the source entity id with the notification.
The existing examples don't leverage this new field, but that will
change when I work on the color sliders PR.
I have been careful not to use the word "events" in describing the
notification message structs because they are not capital-E `Events` at
this time. That may change depending on the outcome of discussions.
@alice-i-cecile
# Objective
- Add 1-bounce RT GI
## Solution
- Implement a very very basic version of ReSTIR GI
https://d1qx31qr3h6wln.cloudfront.net/publications/ReSTIR%20GI.pdf
- Pretty much a copy of the ReSTIR DI code, but adjusted for GI.
- Didn't implement add more spatial samples, or do anything needed for
better quality.
- Didn't try to improve perf at all yet (it's actually faster than DI
though, unfortunately 😅)
- Didn't spend any time cleaning up the shared abstractions between
DI/GI
---
## Showcase
<img width="2564" height="1500" alt="image"
src="https://github.com/user-attachments/assets/1ff7be1c-7d7d-4e53-8aa6-bcec1553db3f"
/>
# Objective
- Rebase of https://github.com/bevyengine/bevy/pull/12561 , note that
this is blocked on "up-streaming
[iyes_perf_ui](https://crates.io/crates/iyes_perf_ui)" , but that work
seems to also be stalled
> Frame time is often more important to know than FPS but because of the
temporal nature of it, just seeing a number is not enough. Seeing a
graph that shows the history makes it easier to reason about
performance.
## Solution
> This PR adds a bar graph of the frame time history.
>
> Each bar is scaled based on the frame time where a bigger frame time
will give a taller and wider bar.
>
> The color also scales with that frame time where red is at or bellow
the minimum target fps and green is at or above the target maximum frame
rate. Anything between those 2 values will be interpolated between green
and red based on the frame time.
>
> The algorithm is highly inspired by this article:
https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
## Testing
- Ran `cargo run --example fps_overlay --features="bevy_dev_tools"`
---------
Co-authored-by: IceSentry <c.giguere42@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Related to #19024.
## Solution
- This is a mix of several ways to get rid of weak handles. The primary
strategy is putting strong asset handles in resources that the rendering
code clones into its pipelines (or whatever).
- This does not handle every remaining case, but we are slowly clearing
them out.
## Testing
- `anti_aliasing` example still works.
- `fog_volumes` example still works.
# Objective
Add interpolation in HSL and HSV colour spaces for UI gradients.
## Solution
Added new variants to `InterpolationColorSpace`: `Hsl`, `HslLong`,
`Hsv`, and `HsvLong`, along with mix functions to the `gradients` shader
for each of them.
#### Limitations
* Didn't include increasing and decreasing path support, it's not
essential and can be done in a follow up if someone feels like it.
* The colour conversions should really be performed before the colours
are sent to the shader but it would need more changes and performance is
good enough for now.
## Testing
```cargo run --example gradients```
# Objective
#19649 introduced new `*_if_new` and `*_by_bundle_id_*` variations to
`EntityClonerBuilder` filtering functionality, which resulted in
increase in method permutations - there are now 8 allow variants to
support various id types and 2 different insert modes.
## Solution
This PR introduces a new trait `FilterableIds` to unify all id types and
their `IntoIterator` implementations, which is somewhat similar to
`WorldEntityFetch`. It supports `TypeId`, `ComponentId` and `BundleId`,
allowing us to reduce the number of `allow` methods to 4: `allow`,
`allow_if_new`, `allow_by_ids`, `allow_by_ids_if_new`. The function
signature is a bit less readable now, but the docs mention types that
can be passed in.
## Testing
All existing tests pass, performance is unchanged.
---------
Co-authored-by: urben1680 <55257931+urben1680@users.noreply.github.com>
# Objective
`PickingPlugin` and `PointerInputPlugin` were kinda weird being both a
plugin and a resource.
## Solution
Extract the resource functionality of `PickingPlugin` and
`PointerInputPlugin` into new resources
## Testing
`mesh_picking` and `sprite_picking`
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Fixes#19910.
## Solution
- First, allow extraction function to be FnMut instead of Fn. FnMut is a
superset of Fn anyway, and we only ever call this function once at a
time (we would never call this in parallel for different pairs of worlds
or something).
- Run the `RenderStartup` schedule in the extract function with a flag
to only do it once.
- Remove all the `MainRender` stuff.
One sad part here is that now the `RenderStartup` blocks extraction. So
for pipelined rendering, our simulation will be blocked on the first
frame while we set up all the rendering resources. I don't see this as a
big loss though since A) that is fundamentally what we want here -
extraction **has to** run after `RenderStartup`, and the only way to do
better is to somehow run `RenderStartup` in parallel with the first
simulation frame, and B) without `RenderStartup` the **entire** app was
blocked on initializing render resources during Plugin construction - so
we're not really losing anything here.
## Testing
- I ran the `custom_post_processing` example (which was ported to use
`RenderStartup` in #19886) and it still works.
# Objective
- prepare bevy_light for split
- make struct named better
- put it where it belongs
## Solution
- do those things
## Testing
- 3d_scene, lighting
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- get closer to being able to load gltfs without using bevy_render
## Solution
- Split bevy_camera out of bevy_render
- Builds on #19943
- Im sorry for the big diff, i tried to minimize it as much as i can by
using re-exports. This also prevents most breaking changes, but there
are still a couple.
## Testing
- 3d_scene looks good
# Objective
- The usage of ComponentId is quite confusing: events are not
components. By newtyping this, we can prevent stupid mistakes, avoid
leaking internal details and make the code clearer for users and engine
devs reading it.
- Adopts https://github.com/bevyengine/bevy/pull/19755
---------
Co-authored-by: oscar-benderstone <oscarbenderstone@gmail.com>
Co-authored-by: Oscar Bender-Stone <88625129+oscar-benderstone@users.noreply.github.com>
# Objective
Move Bevy UI's rendering into a dedicated crate.
Motivations:
* Allow the UI renderer to be used with other UI frameworks than
`bevy_ui`.
* Allow for using alternative renderers like Vello with `bevy_ui`.
* It's difficult for rendering contributors to make changes and
improvements to the UI renderer as it requires in-depth knowledge of the
UI implementation.
## Solution
Move the `render` and `ui_material` modules from `bevy_ui` into a new
crate `bevy_ui_render`.
## Testing
Important examples to check are `testbed_ui`, `testbed_full_ui`,
`ui_material`, `viewport_node` and `gradients`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Allow combinator and pipe systems to delay validation of the second
system, while still allowing the second system to be skipped.
Fixes#18796
Allow fallible systems to be used as one-shot systems, reporting errors
to the error handler when used through commands.
Fixes#19722
Allow fallible systems to be used as run conditions, including when used
with combinators. Alternative to #19580.
Always validate parameters when calling the safe
`run_without_applying_deferred`, `run`, and `run_readonly` methods on a
`System`.
## Solution
Have `System::run_unsafe` return a `Result`.
We want pipe systems to run the first system before validating the
second, since the first system may affect whether the second system has
valid parameters. But if the second system skips then we have no output
value to return! So, pipe systems must return a `Result` that indicates
whether the second system ran.
But if we just make pipe systems have `Out = Result<B::Out>`, then
chaining `a.pipe(b).pipe(c)` becomes difficult. `c` would need to accept
the `Result` from `a.pipe(b)`, which means it would likely need to
return `Result` itself, giving `Result<Result<Out>>`!
Instead, we make *all* systems return a `Result`! We move the handling
of fallible systems from `IntoScheduleConfigs` and `IntoObserverSystem`
to `SystemParamFunction` and `ExclusiveSystemParamFunction`, so that an
infallible system can be wrapped before being passed to a combinator.
As a side effect, this enables fallible systems to be used as run
conditions and one-shot systems.
Now that the safe `run_without_applying_deferred`, `run`, and
`run_readonly` methods return a `Result`, we can have them perform
parameter validation themselves instead of requiring each caller to
remember to call them. `run_unsafe` will continue to not validate
parameters, since it is used in the multi-threaded executor when we want
to validate and run in separate tasks.
Note that this makes type inference a little more brittle. A function
that returns `Result<T>` can be considered either a fallible system
returning `T` or an infallible system returning `Result<T>` (and this is
important to continue supporting `pipe`-based error handling)! So there
are some cases where the output type of a system can no longer be
inferred. It will work fine when directly adding to a schedule, since
then the output type is fixed to `()` (or `bool` for run conditions).
And it will work fine when `pipe`ing to a system with a typed input
parameter.
I used a dedicated `RunSystemError` for the error type instead of plain
`BevyError` so that skipping a system does not box an error or capture a
backtrace.
# Objective
- First step towards #279
## Solution
Makes the necessary internal data structure changes in order to allow
system removal to be added in a future PR: `Vec`s storing systems and
system sets in `ScheduleGraph` have been replaced with `SlotMap`s.
See the included migration guide for the required changes.
## Testing
Internal changes only and no new features *should* mean no new tests are
requried.
# Objective
- This unblocks some work I am doing for #19887.
## Solution
- Rename `RenderGraphApp` to `RenderGraphExt`.
- Implement `RenderGraphExt` for `World`.
- Change `SubApp` and `App` to call the `World` impl.
# Objective
- Progress towards #19024.
## Solution
- Remove `Handle::Weak`!
If users were relying on `Handle::Weak` for some purpose, they can
almost certainly replace it with raw `AssetId` instead. If they cannot,
they can make their own enum that holds either a Handle or an AssetId.
In either case, we don't need weak handles!
Sadly we still need Uuid handles since we rely on them for "default"
assets and "invalid" assets, as well as anywhere where a component wants
to impl default with a non-defaulted asset handle. One step at a time
though!
# Objective
During the migration to required components a lot of things were changed
around and somehow the draw order for some UI elements ended up
depending on the system ordering in `RenderSystems::Queue`, which can
sometimes result in the elements being drawn in the wrong order.
Fixes#19674
## Solution
* Added some more `stack_z_offsets` constants and used them to enforce
an explicit ordering.
* Removed the `stack_index: u32` field from `ExtractedUiNodes` and
replaced it with a `z_order: f32` field.
These changes should fix all the ordering problems.
## Testing
I added a nine-patched bordered node with a navy background color to the
slice section of the `testbed_ui` example.
The border should always be drawn above the background color.
# Objective
Change `ScrollPosition` to newtype `Vec2`. It's easier to work with a
`Vec2` wrapper than individual fields.
I'm not sure why this wasn't newtyped to start with. Maybe the intent
was to support responsive coordinates eventually but that probably isn't
very useful or straightforward to implement. And even if we do want to
support responsive coords in the future, it can newtype `Val2`.
## Solution
Change `ScrollPosition` to newtype `Vec2`.
Also added some extra details to the doc comments.
## Testing
Try the `scroll` example.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Because we want to be able to support more notification options in the
future (in addition to just using registered one-shot systems), the
`Option<SystemId>` notifications have been changed to a new enum,
`Callback`.
@alice-i-cecile
Currently, our specialization API works through a series of wrapper
structs and traits, which make things confusing to follow and difficult
to generalize.
This pr takes a different approach, where "specializers" (types that
implement `Specialize`) are composable, but "flat" rather than composed
of a series of wrappers. The key is that specializers don't *produce*
pipeline descriptors, but instead *modify* existing ones:
```rs
pub trait Specialize<T: Specializable> {
type Key: SpecializeKey;
fn specialize(
&self,
key: Self::Key,
descriptor: &mut T::Descriptor
) -> Result<Canonical<Self::Key>, BevyError>;
}
```
This lets us use some derive magic to stick multiple specializers
together:
```rs
pub struct A;
pub struct B;
impl Specialize<RenderPipeline> for A { ... }
impl Specialize<RenderPipeline> for A { ... }
#[derive(Specialize)]
#[specialize(RenderPipeline)]
struct C {
// specialization is applied in struct field order
applied_first: A,
applied_second: B,
}
type C::Key = (A::Key, B::Key);
```
This approach is much easier to understand, IMO, and also lets us
separate concerns better. Specializers can be placed in fully separate
crates/modules, and key computation can be shared as well.
The only real breaking change here is that since specializers only
modify descriptors, we need a "base" descriptor to work off of. This can
either be manually supplied when constructing a `Specializer` (the new
collection replacing `Specialized[Render/Compute]Pipelines`), or
supplied by implementing `HasBaseDescriptor` on a specializer. See
`examples/shader/custom_phase_item.rs` for an example implementation.
## Testing
- Did some simple manual testing of the derive macro, it seems robust.
---
## Showcase
```rs
#[derive(Specialize, HasBaseDescriptor)]
#[specialize(RenderPipeline)]
pub struct SpecializeMeshMaterial<M: Material> {
// set mesh bind group layout and shader defs
mesh: SpecializeMesh,
// set view bind group layout and shader defs
view: SpecializeView,
// since type SpecializeMaterial::Key = (),
// we can hide it from the wrapper's external API
#[key(default)]
// defer to the GetBaseDescriptor impl of SpecializeMaterial,
// since it carries the vertex and fragment handles
#[base_descriptor]
// set material bind group layout, etc
material: SpecializeMaterial<M>,
}
// implementation generated by the derive macro
impl <M: Material> Specialize<RenderPipeline> for SpecializeMeshMaterial<M> {
type Key = (MeshKey, ViewKey);
fn specialize(
&self,
key: Self::Key,
descriptor: &mut RenderPipelineDescriptor
) -> Result<Canonical<Self::Key>, BevyError> {
let mesh_key = self.mesh.specialize(key.0, descriptor)?;
let view_key = self.view.specialize(key.1, descriptor)?;
let _ = self.material.specialize((), descriptor)?;
Ok((mesh_key, view_key));
}
}
impl <M: Material> HasBaseDescriptor<RenderPipeline> for SpecializeMeshMaterial<M> {
fn base_descriptor(&self) -> RenderPipelineDescriptor {
self.material.base_descriptor()
}
}
```
---------
Co-authored-by: Tim Overbeek <158390905+Bleachfuel@users.noreply.github.com>
# Objective
- A step towards #19024.
- `AnimationGraph` can serialize raw `AssetId`s. However for normal
handles, this is a runtime ID. This means it is unlikely that the
`AssetId` will correspond to the same asset after deserializing -
effectively breaking the graph.
## Solution
- Stop allowing `AssetId` to be serialized by `AnimationGraph`.
Serializing a handle with no path is now an error.
- Add `MigrationSerializedAnimationClip`. This is an untagged enum for
serde, meaning that it will take the first variant that deserializes. So
it will first try the "modern" version, then it will fallback to the
legacy version.
- Add some logging/error messages to explain what users should do.
Note: one limitation here is that this removes the ability to serialize
and deserialize UUIDs. In theory, someone could be using this to have a
"default" animation. If someone inserts an empty `AnimationClip` into
the `Handle::default()`, this **might** produce a T-pose. It might also
do nothing though. Unclear! I think this is worth the risk for
simplicity as it seems unlikely that people are sticking UUIDs in here
(or that you want a default animation in **any** AnimationGraph).
## Testing
- Ran `cargo r --example animation_graph -- --save` on main, then ran
`cargo r --example animation_graph` on this PR. The PR was able to load
the old data (after #19631).
# Objective
It's odd that `TextShadow` is accessible by importing `bevy::ui::*` but
`Text` isn't.
Move the `TextShadow` component to `text` widget module and move its
type registration to the `build_text_interop` function.
# Objective
This PR introduces Bevy Feathers, an opinionated widget toolkit and
theming system intended for use by the Bevy Editor, World Inspector, and
other tools.
The `bevy_feathers` crate is incomplete and hidden behind an
experimental feature flag. The API is going to change significantly
before release.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
*Step towards https://github.com/bevyengine/bevy/issues/19686*
We now have all the infrastructure in place to migrate Bevy's default
behavior when loading glTF files to respect their coordinate system.
Let's start migrating! For motivation, see the issue linked above
## Solution
- Introduce a feature flag called `gltf_convert_coordinates_default`
- Currently,`GltfPlugin::convert_coordinates` defaults to `false`
- If `gltf_convert_coordinates_default` is enabled,
`GltfPlugin::convert_coordinates` will default to `true`
- If `gltf_convert_coordinates_default` is not enabled *and*
`GltfPlugin::convert_coordinates` is false, we assume the user is
implicitly using the old behavior. Print a warning *once* in that case,
but only when a glTF was actually loaded
- A user can opt into the new behavior either
- Globally, by enabling `gltf_convert_coordinates_default` in their
`Cargo.toml`
- Globally, by enabling `GltfPlugin::convert_coordinates`
- Per asset, by enabling `GltfLoaderSettings::convert_coordinates`
- A user can explicitly opt out of the new behavior and silence the
warning by
- Enabling `gltf_convert_coordinates_default` in their `Cargo.toml` and
disabling `GltfPlugin::convert_coordinates`
- This PR also moves the existing release note into a migration guide
Note that I'm very open to change any features, mechanisms, warning
texts, etc. as needed :)
## Future Work
- This PR leaves all examples fully functional by not enabling this flag
internally yet. A followup PR will enable it as a `dev-dependency` and
migrate all of our examples involving glTFs to the new behavior.
- After 0.17 (and the RC before) lands, we'll gather feedback to see if
anything breaks or the suggested migration is inconvenient in some way
- If all goes well, we'll kill this flag and change the default of
`GltfPlugin::convert_coordinates` to `true` in 0.18
## Testing
- Ran examples with and without the flag
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: AlephCubed <76791009+AlephCubed@users.noreply.github.com>
# Objective
- add support for alternate zstd backend through `zstd` for faster
decompression
## Solution
- make existing `zstd` feature only specify that support is required,
disambiguate which backend to use via two other features `zstd_native`
and `zstd_rust`.
- Similar to the approach taken by #18411, but we keep current behavior
by defaulting to the rust implementation because its safer, and isolate
this change.
NOTE: the default feature-set may seem to not currently require `zstd`,
but it does, it is enabled transitively by the `tonemapping_luts`
feature, which is a default feature. Thus this does not add default
features.
## Testing
- Cargo clippy on both feature combinations
# Objective
Upgrade to `wgpu` version `25.0`.
Depends on https://github.com/bevyengine/naga_oil/pull/121
## Solution
### Problem
The biggest issue we face upgrading is the following requirement:
> To facilitate this change, there was an additional validation rule put
in place: if there is a binding array in a bind group, you may not use
dynamic offset buffers or uniform buffers in that bind group. This
requirement comes from vulkan rules on UpdateAfterBind descriptors.
This is a major difficulty for us, as there are a number of binding
arrays that are used in the view bind group. Note, this requirement does
not affect merely uniform buffors that use dynamic offset but the use of
*any* uniform in a bind group that also has a binding array.
### Attempted fixes
The easiest fix would be to change uniforms to be storage buffers
whenever binding arrays are in use:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<uniform> lights: types::Lights;
#else
@group(0) @binding(0) var<storage> view: array<View>;
@group(0) @binding(1) var<storage> lights: array<types::Lights>;
#endif
```
This requires passing the view index to the shader so that we know where
to index into the buffer:
```wgsl
struct PushConstants {
view_index: u32,
}
var<push_constant> push_constants: PushConstants;
```
Using push constants is no problem because binding arrays are only
usable on native anyway.
However, this greatly complicates the ability to access `view` in
shaders. For example:
```wgsl
#ifdef BINDING_ARRAYS_ARE_USED
mesh_view_bindings::view.view_from_world[0].z
#else
mesh_view_bindings::view[mesh_view_bindings::view_index].view_from_world[0].z
#endif
```
Using this approach would work but would have the effect of polluting
our shaders with ifdef spam basically *everywhere*.
Why not use a function? Unfortunately, the following is not valid wgsl
as it returns a binding directly from a function in the uniform path.
```wgsl
fn get_view() -> View {
#if BINDING_ARRAYS_ARE_USED
let view_index = push_constants.view_index;
let view = views[view_index];
#endif
return view;
}
```
This also poses problems for things like lights where we want to return
a ptr to the light data. Returning ptrs from wgsl functions isn't
allowed even if both bindings were buffers.
The next attempt was to simply use indexed buffers everywhere, in both
the binding array and non binding array path. This would be viable if
push constants were available everywhere to pass the view index, but
unfortunately they are not available on webgpu. This means either
passing the view index in a storage buffer (not ideal for such a small
amount of state) or using push constants sometimes and uniform buffers
only on webgpu. However, this kind of conditional layout infects
absolutely everything.
Even if we were to accept just using storage buffer for the view index,
there's also the additional problem that some dynamic offsets aren't
actually per-view but per-use of a setting on a camera, which would
require passing that uniform data on *every* camera regardless of
whether that rendering feature is being used, which is also gross.
As such, although it's gross, the simplest solution just to bump binding
arrays into `@group(1)` and all other bindings up one bind group. This
should still bring us under the device limit of 4 for most users.
### Next steps / looking towards the future
I'd like to avoid needing split our view bind group into multiple parts.
In the future, if `wgpu` were to add `@builtin(draw_index)`, we could
build a list of draw state in gpu processing and avoid the need for any
kind of state change at all (see
https://github.com/gfx-rs/wgpu/issues/6823). This would also provide
significantly more flexibility to handle things like offsets into other
arrays that may not be per-view.
### Testing
Tested a number of examples, there are probably more that are still
broken.
---------
Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/14328
- `DynamicMap::drain` was broken (indices weren't cleared, causing a
panic when reading later)
- `PartialReflect::apply` was broken for maps and sets, because they
don't remove entries from the `self` map that aren't in the applied map.
- I discovered this bug when implementing MapEntities on a Component
containing a `HashMap<Entity, _>`. Because `apply` is used to reapply
the changes to the reflected map, the map ended up littered with a ton
of outdated entries.
## Solution
- Remove the separate `Vec` in `DynamicMap` and use the `HashTable`
directly, like it is in `DynamicSet`.
- Replace `MapIter` by `Box<dyn Iterator>` (like for `DynamicSet`), and
`Map::get_at` and `Map::get_at_mut` which are now unused.
- Now assume `DynamicMap` types are unordered and adjust documentation
accordingly.
- Fix documentation of `DynamicSet` (ordered -> unordered)
- Added `Map::retain` and `Set::retain`, and use them to remove excess
entries in `PartialReflect::apply` implementations.
## Testing
- Added `map::tests::apply` and `set::tests::apply` to validate
`<DynamicMap as PartialReflect>::apply` and `<DynamicSet as
PartialReflect>::apply`
# Objective
- Followup to https://github.com/bevyengine/bevy/pull/19633
- As discussed, it's a bit cumbersome to specify that you want the
correct orientation every single time
- Also, glTFs loaded from third parties will still be loaded incorrectly
## Solution
- Allow opting into the new behavior globally or per-asset
- Also improved some docs while on it :)
## Testing
- Ran the animation examples
- Ran the test scene from the last PR with all configuration
combinations
# Objective
Further tests after #19326 showed that configuring `EntityCloner` with
required components is bug prone and the current design has several
weaknesses in it's API:
- Mixing `EntityClonerBuilder::allow` and `EntityClonerBuilder::deny`
requires extra care how to support that which has an impact on
surrounding code that has to keep edge cases in mind. This is especially
true for attempts to fix the following issues. There is no use-case
known (to me) why someone would mix those.
- A builder with `EntityClonerBuilder::allow_all` configuration tries to
support required components like `EntityClonerBuilder::deny_all` does,
but the meaning of that is conflicting with how you'd expect things to
work:
- If all components should be cloned except component `A`, do you also
want to exclude required components of `A` too? Or are these also valid
without `A` at the target entity?
- If `EntityClonerBuilder::allow_all` should ignore required components
and not add them to be filtered away, which purpose has
`EntityClonerBuilder::without_required_components` for this cloner?
- Other bugs found with the linked PR are:
- Denying `A` also denies required components of `A` even when `A` does
not exist at the source entity
- Allowing `A` also allows required components of `A` even when `A` does
not exist at the source entity
- Adding `allow_if_new` filters to the cloner faces the same issues and
require a common solution to dealing with source-archetype sensitive
cloning
Alternative to #19632 and #19635.
# Solution
`EntityClonerBuilder` is made generic and split into
`EntityClonerBuilder<OptOut>` and `EntityClonerBuilder<OptIn>`
For an overview of the changes, see the migration guide. It is generally
a good idea to start a review of that.
## Algorithm
The generic of `EntityClonerBuilder` contains the filter data that is
needed to build and clone the entity components.
As the filter needs to be borrowed mutably for the duration of the
clone, the borrow checker forced me to separate the filter value and all
other fields in `EntityCloner`. The latter are now in the
`EntityClonerConfig` struct. This caused many changed LOC, sorry.
To make reviewing easier:
1. Check the migration guide
2. Many methods of `EntityCloner` now just call identitcal
`EntityClonerConfig` methods with a mutable borrow of the filter
3. Check `EntityClonerConfig::clone_entity_internal` which changed a bit
regarding the filter usage that is now trait powered (`CloneByFilter`)
to support `OptOut`, `OptIn` and `EntityClonerFilter` (an enum combining
the first two)
4. Check `OptOut` type that no longer tracks required components but has
a `insert_mode` field
5. Check `OptIn` type that has the most logic changes
# Testing
I added a bunch of tests that cover the new logic parts and the fixed
issues.
Benchmarks are in a comment a bit below which shows ~4% to 9%
regressions, but it varied wildly for me. For example at one run the
reflection-based clonings were on-par with main while the other are not,
and redoing that swapped the situation for both.
It would be really cool if I could get some hints how to get better
benchmark results or if you could run them on your machine too.
Just be aware this is not a Performance PR but a Bugfix PR, even if I
smuggled in some more functionalities. So doing changes to
`EntityClonerBuilder` is kind of required here which might make us bite
the bullet.
---------
Co-authored-by: eugineerd <70062110+eugineerd@users.noreply.github.com>
# Objective
- Related to #19024.
## Solution
- Remove the `FULLSCREEN_SHADER_HANDLE` `weak_handle` with a resource
holding the shader handle.
- This also changes us from using `load_internal_asset` to
`embedded_asset`/`load_embedded_asset`.
- All uses have been migrated to clone the `FullscreenShader` resource
and use its `to_vertex_state` method.
## Testing
- `anti_aliasing` example still works.
- `bloom_3d` example still works.
---------
Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com>
# Objective
An attempt to start building a base for first-party tilemaps (#13782).
The objective is to create a very simple tilemap chunk rendering plugin
that can be used as a building block for 3rd-party tilemap crates, and
eventually a first-party tilemap implementation.
## Solution
- Introduces two user-facing components, `TilemapChunk` and
`TilemapChunkIndices`, and a new material `TilemapChunkMaterial`.
- `TilemapChunk` holds the chunk and tile sizes, and the tileset image
- The tileset image is expected to be a layered image for use with
`texture_2d_array`, with the assumption that atlases or multiple images
would go through an asset loader/processor. Not sure if that should be
part of this PR or not..
- `TilemapChunkIndices` holds a 1d representation of all of the tile's
Option<u32> index into the tileset image.
- Indices are fixed to the size of tiles in a chunk (though maybe this
should just be an assertion instead?)
- Indices are cloned and sent to the shader through a u32 texture.
## Testing
- Initial testing done with the `tilemap_chunk` example, though I need
to include some way to update indices as part of it.
- Tested wasm with webgl2 and webgpu
- I'm thinking it would probably be good to do some basic perf testing.
---
## Showcase
```rust
let chunk_size = UVec2::splat(64);
let tile_size = UVec2::splat(16);
let indices: Vec<Option<u32>> = (0..chunk_size.x * chunk_size.y)
.map(|_| rng.gen_range(0..5))
.map(|i| if i == 0 { None } else { Some(i - 1) })
.collect();
commands.spawn((
TilemapChunk {
chunk_size,
tile_size,
tileset,
},
TilemapChunkIndices(indices),
));
```

# Objective
- Notice a word duplication typo
- Small quest to fix similar or nearby typos with my faithful companion
`\b(\w+)\s+\1\b`
## Solution
Fix em
# Objective
Some methods and commands carelessly overwrite `Relationship`
components. This may overwrite additional data stored at them which is
undesired.
Part of #19589
## Solution
A new private method will be used instead of insert:
`modify_or_insert_relation_with_relationship_hook_mode`.
This method behaves different to `insert` if `Relationship` is a larger
type than `Entity` and already contains this component. It will then use
the `modify_component` API and a new `Relationship::set_risky` method to
set the related entity, keeping all other data untouched.
For the `replace_related`(`_with_difference`) methods this also required
a `InsertHookMode` parameter for efficient modifications of multiple
children. The changes here are limited to the non-public methods.
I would appreciate feedback if this is all good.
# Testing
Added tests of all methods that previously could reset `Relationship`
data.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Add support for interpolation in OKLab and OKLCH color spaces for UI
gradients.
## Solution
* New `InterpolationColorSpace` enum with `OkLab`, `OkLch`, `OkLchLong`,
`Srgb` and `LinearRgb` variants.
* Added a color space specialization to the gradients pipeline.
* Added support for interpolation in OkLCH and OkLAB color spaces to the
gradients shader. OKLCH interpolation supports both short and long hue
paths. This is mostly based on the conversion functions from
`bevy_color` except that interpolation in polar space uses radians.
* Added `color_space` fields to each gradient type.
## Testing
The `gradients` example has been updated to demonstrate the different
color interpolation methods.
Press space to cycle through the different options.
---
## Showcase
