# Objective
A more robust scrolling example that doesn't require `Pickable {
should_block_lower: false, .. }` or `Pickable::IGNORE`, and properly
handles nested scrolling nodes.
The current example shows nested scrolling, but this is only functional
because the parent scrolls along a different axis than the children.
## Solution
Instead of only scrolling the top node that is found in the `HoverMap`
we trigger the `OnScroll` event on it.
This event then propagates up the hierarchy until any scrolling node
that has room to scroll along that axis consumes the event.
The now redundant `Pickable` components were removed from the example.
The “Nested Scrolling Lists” portion was adjusted to show the new
reliable nested scrolling.
## Testing
Check out the example. It should work just as it did before.
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
I was building out a diagnostics panel in egui when I noticed that I
could specify the max history length for the
`FrameTimeDiagnosticsPlugin`, but not for the
`EntityCountDiagnosticsPlugin`. The objective was to harmonize the two,
making the diagnostic history length configurable for both.
## Solution
I added a `EntityCountDiagnosticsPlugin::new`, and a `Default` impl that
matches `FrameTimeDiagnosticsPlugin`.
This is a breaking change, given the plugin had no fields previously.
## Testing
I did not test this.
# 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
The false and true arguments for the select statement in `lerp_hue_long`
are misordered, resulting in it taking the wrong hue path:

## Solution
Swap the arguments around.
Also fixed another case I found during testing. The hue was interpolated
even when it is undefined for one of the endpoints (for example in a
gradient from black to yellow). In those cases it shouldn't interpolate,
instead it should return the hue of the other end point.
## Testing
I added a `linear_gradient` module to the testbed `ui` example, run
with:
```
cargo run --example testbed_ui
```
In the linear gradients screen (press space to switch) it shows a column
of red to yellow linear gradients. The last gradient in the column uses
the OKLCH long path, which should look like this:

matching the same gradient in CSS:
https://jsfiddle.net/fevshkdy/14/
if the correct hue path is chosen.
# 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```
[Explanation](https://bevyengine.org/learn/contribute/helping-out/explaining-examples/)
for the 3d shapes example.
This shares a lot of detail with the [2d
shapes](https://github.com/bevyengine/bevy/pull/19211) example, so it's
similar in structure. The explanation for why asset handles are not
components has been copied over for now with minor adjustment, I'll do
another editing pass on this to make it match the surrounding context
and focus before taking it out of drafts.
---------
Co-authored-by: theotherphil <phil.j.ellison@gmail.com>
Co-authored-by: Carter Weinberg <weinbergcarter@gmail.com>
# Objective
- Fixes#13872 (also mentioned in #17167)
## Solution
- Added conditional padding fields to the shader uniform
## Alternatives
### 1- Use a UVec4
Replace the `u32` field in `MyExtension` by a `UVec4` and only use the
`x` coordinate.
(This was the original approach, but for consistency with the rest of
the codebase, separate padding fields seem to be preferred)
### 2- Don't fix it, unlist it
While the fix is quite simple, it does muddy the waters a tiny bit due
to `quantize_steps` now being a UVec4 instead of a simple u32. We could
simply remove this example from the examples that support WebGL2.
## Testing
- Ran the example locally on WebGL2 (and native Vulkan) successfully
# Objective
- make lights usable without bevy_render
## Solution
- make a new crate for lights to live in
## Testing
- 3d_scene, lighting, volumetric_fog, ssr, transmission, pcss,
light_textures
Note: no breaking changes because of re-exports, except for light
textures, which were introduced this cycle so it doesn't matter anyways
# 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.
A few versions ago, wgpu made it possible to set shader entry point to
`None`, which will select the correct entry point in file where only a
single entrypoint is specified. This makes it possible to implement
`Default` for pipeline descriptors. This PR does so and attempts to
`..default()` everything possible.
# 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
- Example `light_textures` exit if feature `pbr_light_textures` is not
enabled. this is checked in code instead of using `required-features`
- Same for `clustered_decals` and `par_clustered_decals`
- Those examples are also using `eprintln`
- Those examples are using `process:exit` to exit
## Solution
- Use `required-features`
- Use logs
- Use `AppExit`
# 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
- This example uses a FromWorld impl to initialize a resource on startup
- #19887
## Solution
- Use RenderStartup instead
## Testing
- The example still works as expected
# Objective
I was lurking and noticed that some links to the Bevy website were not
updated in newer code (`bevyengine.org` -> `bevy.org`).
## Solution
- Look for `bevyengine.org` occurrences in the current code, replace
them with `bevy.org`.
## Testing
- Did you test these changes? If so, how? I visited the Bevy website!
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
## Longer term
- Maybe add a lint to flag references to the old website but I don't
know how to do that. But not sure it's needed as the more time will pass
the less it will be relevant.
# Objective
Contributes to #18238
Updates the `log_layers_ecs`, example to use the `children!` macro.
Note that I did not use a macro, nor `Children::spawn` for the outer
layer. Since the `EventReader` is borrowed mutably, any `.map` I did on
`events.read()` was going to have the reference outlive the function
body. I believe this scope of change is correct for the PR.
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## Testing
- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- see above
---
## Showcase
n/a
## Migration Guide
n/a
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.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
add support for light textures (also known as light cookies, light
functions, and light projectors)

## Solution
- add components:
```rs
/// Add to a [`PointLight`] to add a light texture effect.
/// A texture mask is applied to the light source to modulate its intensity,
/// simulating patterns like window shadows, gobo/cookie effects, or soft falloffs.
pub struct PointLightTexture {
/// The texture image. Only the R channel is read.
pub image: Handle<Image>,
/// The cubemap layout. The image should be a packed cubemap in one of the formats described by the [`CubemapLayout`] enum.
pub cubemap_layout: CubemapLayout,
}
/// Add to a [`SpotLight`] to add a light texture effect.
/// A texture mask is applied to the light source to modulate its intensity,
/// simulating patterns like window shadows, gobo/cookie effects, or soft falloffs.
pub struct SpotLightTexture {
/// The texture image. Only the R channel is read.
/// Note the border of the image should be entirely black to avoid leaking light.
pub image: Handle<Image>,
}
/// Add to a [`DirectionalLight`] to add a light texture effect.
/// A texture mask is applied to the light source to modulate its intensity,
/// simulating patterns like window shadows, gobo/cookie effects, or soft falloffs.
pub struct DirectionalLightTexture {
/// The texture image. Only the R channel is read.
pub image: Handle<Image>,
/// Whether to tile the image infinitely, or use only a single tile centered at the light's translation
pub tiled: bool,
}
```
- store images to the `RenderClusteredDecals` buffer
- read the image and modulate the lights
- add `light_textures` example to showcase the new features
## Testing
see light_textures example
# Objective
When dragging the slider thumb the thumb is only highlighted while the
pointer is hovering the widget. If the pointer moves off the widget
during a drag the thumb reverts to its normal unhovered colour.
## Solution
Query for `CoreSliderDragState` in the slider update systems and set the
lighter color if the thumb is dragged or hovered.
# 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
Closes#18075
In order to enable a number of patterns for dynamic materials in the
engine, it's necessary to decouple the renderer from the `Material`
trait.
This opens the possibility for:
- Materials that aren't coupled to `AsBindGroup`.
- 2d using the underlying 3d bindless infrastructure.
- Dynamic materials that can change their layout at runtime.
- Materials that aren't even backed by a Rust struct at all.
## Solution
In short, remove all trait bounds from render world material systems and
resources. This means moving a bunch of stuff onto `MaterialProperties`
and engaging in some hacks to make specialization work. Rather than
storing the bind group data in `MaterialBindGroupAllocator`, right now
we're storing it in a closure on `MaterialProperties`. TBD if this has
bad performance characteristics.
## Benchmarks
- `many_cubes`:
`cargo run --example many_cubes --release --features=bevy/trace_tracy --
--vary-material-data-per-instance`:

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

- @DGriffin91's Caldera with 20 unique material types (i.e.
`MaterialPlugin<M>`) and random materials per mesh
`cargo run --release --features=bevy/trace_tracy -- --random-materials`

### TODO
- We almost certainly lost some parallelization from removing the type
params that could be gained back from smarter iteration.
- Test all the things that could have broken.
- ~Fix meshlets~
## Showcase
See [the
example](https://github.com/bevyengine/bevy/pull/19667/files#diff-9d768cfe1c3aa81eff365d250d3cbe5a63e8df63e81dd85f64c3c3cd993f6d94)
for a custom material implemented without the use of the `Material`
trait and thus `AsBindGroup`.

---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
Co-authored-by: IceSentry <c.giguere42@gmail.com>
# 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
- 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),
));
```

This is a bit of a test case in writing the
[explanation](https://bevyengine.org/learn/contribute/helping-out/explaining-examples/)
for an example whose subject (`DistanceFog` as a component on cameras)
is the focus, but isn't that complicated either. Not certain if this
could be an exception or something more common.
Putting the controls below the explanation, as they're more of a
fall-back for the on-screen info (also that's where they were before).
# Objective
- Start the realtime direct lighting work for bevy solari
## Solution
- Setup all the CPU-side code for the realtime lighting path (minus some
parts for the temporal reuse I haven't written yet)
- Implement RIS with 32 samples to choose a good random light
- Don't sample a disk for the directional light, just treat it as a
single point. This is faster and not much worse quality.
## Future
- Spatiotemporal reuse (ReSTIR DI)
- Denoiser (DLSS-RR)
- Light tile optimization for faster light selection
- Indirect lighting (ReSTIR GI)
## Testing
- Run the solari example to see realtime
- Run the solari example with `-- --pathtracer` to see the existing
pathtracer
---
## Showcase
1 frame direct lighting:

Accumulated pathtracer output:

---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fix https://github.com/bevyengine/bevy/issues/19617
# Solution
Add newlines before all impl blocks.
I suspect that at least some of these will be objectionable! If there's
a desired Bevy style for this then I'll update the PR. If not then we
can just close it - it's the work of a single find and replace.
Click to focus is now a global observer.
# Objective
Previously, the "click to focus" behavior was implemented in each
individual headless widget, producing redundant logic.
## Solution
The new scheme is to have a global observer which looks for pointer down
events and triggers an `AcquireFocus` event on the target. This event
bubbles until it finds an entity with `TabIndex`, and then focuses it.
## Testing
Tested the changes using the various examples that have focusable
widgets. (This will become easier to test when I add focus ring support
to the examples, but that's for another day. For now you just have to
know which keys to press.)
## Migration
This change is backwards-compatible. People who want the new behavior
will need to install the new plugin.