Commit Graph

9207 Commits

Author SHA1 Message Date
atlv
dd57db44d9
prepare bevy_light for split (#19965)
# Objective

- prepare bevy_light for split

## Solution

- extract cascade module (this is not strictly necessary for bevy_light)
- clean up imports to be less globby and tangled
- move light specific stuff into light modules
- move light system and type init from pbr into new LightPlugin

## Testing

- 3d_scene, lighting

NOTE TO REVIEWERS: it may help to review commits independently.
2025-07-06 04:11:46 +00:00
atlv
0b771d9f59
move ClusteredDecal to cluster module (#19959)
# Objective

- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera

## Solution

- move ClusteredDecal to cluster module
- Depends on #19957 (because of the imports shuffling around) (draft
until thats merged)

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 19:31:59 +00:00
atlv
7aaf4bbd94
fix a couple typos in CubemapLayout (#19964)
# Objective

- Rob pointed out a couple typos in #19960 (i just did a copy paste, but
the original had an issue)

## Solution

- Fix
2025-07-05 17:05:56 +00:00
atlv
6ab8e0d9c7
move ShadowsEnabled to material (#19963)
# Objective

- Make bevy_light possible

## Solution

- Move non-light stuff out of light module (its a marker for whether a
material should cast shadows: thats a material property not a light
property)

## Testing

- 3d_scene runs
2025-07-05 17:05:14 +00:00
atlv
ced36021d0
move light stuff out of decal cluster (#19962)
# Objective

- Make bevy_light possible

## Solution

- Move light stuff into light module

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 17:04:21 +00:00
atlv
47e99c8285
move Cubemap stuff alongside CubemapFrusta in bevy_camera::primitives (#19955)
# Objective

- Make bevy_light possible

## Solution

- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, cubemap stuff goes next to cubemap stuff.

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 14:40:59 +00:00
atlv
59e8702a65
move calculate_cluster_factors to cluster assign (#19958)
# Objective

- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera

## Solution

- Move some stuff so i can split it out cleanly.

## Testing

- 3d_scene runs
2025-07-05 14:40:33 +00:00
atlv
f987920bbd
Move CubemapLayout out of decal code (#19960)
# Objective

- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera

## Solution

- Move cubemap stuff next to cubemap stuff.

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 14:40:28 +00:00
theotherphil
a869383cda
Minor code readability improvement in enum_utility.access_field (#19961)
Small cleanup copied from https://github.com/bevyengine/bevy/pull/16250
2025-07-05 14:40:23 +00:00
atlv
bdb39cf723
move spot light function into spot light file (#19956)
# Objective

- Make bevy_light possible

## Solution

- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, spotlight stuff goes in spotlight file.

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 14:40:06 +00:00
atlv
d0896bf10a
make cluster assign not depend on RenderAdapter/RenderDevice (#19957)
# Objective

- Make bevy_light possible by making it possible to split out
clusterable into bevy_camera

## Solution

- Use a resource to store cluster settings instead of recalculating it
every time from the render adapter/device

## Testing

- 3d_scene runs
2025-07-05 14:39:41 +00:00
atlv
1b09c4051e
Move Camera3d/2d to bevy_camera (#19953)
# Objective

- define scenes without bevy_render

## Solution

- Move Camera2d/3d components out of bevy_core_pipeline

## Testing

- 3d_scene runs fine

Note: no breaking changes thanks to re-exports
2025-07-05 13:24:28 +00:00
atlv
bfbc6c3d11
move some Visibility stuff to bevy_camera::visibility (#19954)
# Objective

- Make bevy_light possible

## Solution

- Move some stuff it needs out of somewhere it cant depend on. Plus it
makes sense, visibility stuff goes in visibility.

## Testing

- 3d_scene runs

Note: no breaking changes thanks to re-exports
2025-07-05 13:24:20 +00:00
andriyDev
29779e1e18
Use RenderStartup in bevy_ui. (#19901)
# Objective

- Progress towards #19887.

## Solution

- Convert `FromWorld` impls into systems that run in `RenderStartup`.
- Move `UiPipeline` init to `build_ui_render` instead of doing it
separately in `finish`.

Note: I am making several of these systems pub so that users could order
their systems relative to them. This is to match the fact that these
types previously were FromWorld so users could initialize them.

## Testing

- Ran `ui_material`, `ui_texture_slice`, `box_shadow`, and `gradients`
examples and it still worked.
2025-07-05 04:07:23 +00:00
atlv
bd5f924290
Split bevy_camera out of bevy_render (#19949)
# 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
2025-07-04 23:31:16 +00:00
Daniel Skates
560429ebd9
Observer trigger refactor (#19935)
# 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>
2025-07-04 16:27:21 +00:00
atlv
1380a3b7f2
add must_use to register_component_hooks (#19945)
# Objective

- I accidentally left a `register_component_hooks` without actually
adding a hook and didnt notice

## Solution

- mark it must_use so it doesnt happen to other people (maybe this is
just skill issue on me though)
2025-07-04 16:24:46 +00:00
atlv
58feca9b32
refactor(mesh): move Mesh3d and Mesh2d into bevy_mesh (#19943)
# Objective

- another step towards splitting out bevy_camera, this is needed by
visibility systems

## Solution

- move mesh stuff into mesh place

## Testing

- 3d_scene looks fine

No migration needed because of the re-export, that can be another PR
after i split bevy_camera
2025-07-04 16:24:21 +00:00
ickshonpe
b01de70bdd
bevy_ui_render crate (#18703)
# 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>
2025-07-03 23:36:35 +00:00
Nicholas Nethercote
2d02f629b3
bevy_reflect: Remove unnecessary allow(unused_mut). (#19930)
# Objective

The generated `GetTypeRegistration::get_type_registration` method has an
unnecessary `allow(unused_mut)` attribute. It used to be necessary
because it was possible for `registration` to not be modified, but now
there is always at least one modification.

## Solution

Remove the attribute.

## Testing

I checked the `cargo expand` output.
2025-07-03 22:27:58 +00:00
robtfm
eed3085a37
fix panic looking for extension in multibyte unicode paths (#19933)
# Objective

```
2025-07-03T11:48:34.039501Z ERROR panic: thread 'IO Task Pool (6)' panicked at 'byte index 9 is not a char boundary; it is inside '个' (bytes 7..10) of `展示_个人收款码.png`': [...]\crates\bevy_asset\src\path.rs:475
```

## Solution

char_indices
2025-07-03 22:27:07 +00:00
charlotte 🌸
852fb84aa2
Add options for selecting adapter by name and forcing fallback (#19921)
Adds support for:
- `WGPU_ADAPTER_NAME` which will attempt to select a specific adapter
with a given name.
- `WGPU_FORCE_FALLBACK_ADAPTER` which will force fallback to a fallback
(software) renderer, if available.

The first has higher specificity than the second.
2025-07-03 22:26:34 +00:00
Chris Russell
6e918f56d8
Have System::run_unsafe return Result. (#19145)
# 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.
2025-07-03 21:48:09 +00:00
Vadim
ec825d135b
Remove leftover apply deferred example metadata from Cargo.toml (#19939)
I was a bit confused when searching for info about apply deferred, then
I found this metadata without the actual example in the manifest.
2025-07-03 20:42:51 +00:00
Wuketuke
4564a5ba0d
improved the entity_index_map unit test (#19936)
...which previously used a HashSet, whos iter has no ordering guarantee

fixes #19687
i also discovered that the asserted order in the unit test is reversed,
so i fixed that. I dont know if that reversed order is intentional

Edit: i referenced the wrong issue oops
2025-07-03 20:36:09 +00:00
theotherphil
4e32caf027
Fix docs typo (#19937)
Fix a doc comment typo.
2025-07-03 19:02:50 +00:00
Joe Buehler
d16d216083
Add support for returning all Component and values to query method in the Bevy Remote Protocol (#19857)
# Objective

We should have an API with filtering to allow BRP clients to retrieve
all relevant data from the world state. Currently working on adding
examples - but reviews are appreciated! Still semi-WIP while I get my
head around bevy’s reflection and implementation :)

## Solution

This change adds support to query all entities in the world, and returns
all of their Reflected Components with corresponding values. For custom
`Components` it's important to still implement `Reflect` so that this
endpoint returns these. This will be useful for the
`bevy_entity_inspector` so that we can easily get the current world
state. We have modified the existing query API
so that clients can now pass in an empty `components[]` on the JSON
request.

## Testing

Updated example to showcase how to use the new endpoint to get all data:
```rust
/// Create a query_all request to send to the remote Bevy app.
/// This request will return all entities in the app, their components, and their
/// component values.
fn run_query_all_components_and_entities(url: String) -> Result<(), anyhow::Error> {
    let query_all_req = BrpRequest {
        jsonrpc: String::from("2.0"),
        method: String::from(BRP_QUERY_METHOD),
        id: Some(serde_json::to_value(1)?),
        params: None,
    };
    println!("query_all req: {:#?}", query_all_req);
    let query_all_res = ureq::post(&url)
        .send_json(query_all_req)?
        .body_mut()
        .read_json::<serde_json::Value>()?;
    println!("{query_all_res:#}");
    Ok(())
}
```

---

## Showcase
In the `client.rs` example, we can clearly see (assuming the `server.rs`
is running) a query hit for all entities and components:
```text
query_all req: BrpRequest {
    jsonrpc: "2.0",
    method: "bevy/query",
    id: Some(
        Number(1),
    ),
    params: Some(
        Object {
            "data": Object {
                "components": Array [],
                "has": Array [],
                "option": Array [],
            },
            "filter": Object {
                "with": Array [],
                "without": Array [],
            },
            "strict": Bool(false),
        },
    ),
}
```

And in the massive response:
```text
.....
{
      "components": {
        "bevy_window::monitor::Monitor": {
          "name": "\\\\.\\DISPLAY1",
          "physical_height": 1080,
          "physical_position": [
            -1920,
            0
          ],
          "physical_width": 1920,
          "refresh_rate_millihertz": 240000,
          "scale_factor": 1.25,
          "video_modes": [
            {
              "bit_depth": 32,
              "physical_size": [
                1920,
                1080
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1680,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1600,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1440,
                900
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1400,
                1050
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1366,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1360,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                1024
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                960
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                800
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                720
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1280,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1152,
                864
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                1024,
                768
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                800,
                600
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                480
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                640,
                400
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                512,
                384
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                400,
                300
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                240
              ],
              "refresh_rate_millihertz": 240000
            },
            {
              "bit_depth": 32,
              "physical_size": [
                320,
                200
              ],
              "refresh_rate_millihertz": 240000
            }
          ]
        }
      },
      "entity": 4294967267
    },
....
```

What's also really cool about this and `bevy_reflect` is that we also
get custom components returned as well (see below for `"server::Cube":
1.0` as the custom reflected struct specified in `server.rs`:

```text
{
      "components": {
        "bevy_render::primitives::Aabb": {
          "center": [
            0.0,
            0.0,
            0.0
          ],
          "half_extents": [
            0.5,
            0.5,
            0.5
          ]
        },
        "bevy_render::view::visibility::InheritedVisibility": true,
        "bevy_render::view::visibility::ViewVisibility": true,
        "bevy_render::view::visibility::Visibility": "Inherited",
        "bevy_transform::components::global_transform::GlobalTransform": [
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          0.0,
          0.0,
          1.0,
          0.0,
          2.4572744369506836,
          0.0
        ],
        "bevy_transform::components::transform::Transform": {
          "rotation": [
            0.0,
            0.0,
            0.0,
            1.0
          ],
          "scale": [
            1.0,
            1.0,
            1.0
          ],
          "translation": [
            0.0,
            2.4572744369506836,
            0.0
          ]
        },
        "bevy_transform::components::transform::TransformTreeChanged": null,
        "server::Cube": 1.0
      },
```

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2025-07-03 18:51:32 +00:00
Christian Hughes
ebf87f56ef
Use SlotMaps to store systems and system sets in Schedules (#19352)
# 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.
2025-07-03 18:50:54 +00:00
Emerson Coskey
bbf91a6964
spec_v2: minor revisions (#19923)
- renamed `spec_v2` related modules, that commit slipped through the
other pr #17373
- revised struct and trait docs for clarity, and gave a short intro to
specialization
- turns out the derive macro was broken, fixed that too
2025-07-03 17:49:04 +00:00
James Lucas
0f1eebed38
Fixing sprite pixel space point computation for sprites with zero custom_size (#19907)
# Objective

Current implementation of `Sprite::compute_pixel_space_point` always
returns the sprite centre as an `Ok` point when the `custom_size` is set
to `Vec2::ZERO`. This leads to unexpected behaviour. For example, it
causes these sprites to block all interactions with other sprites in the
picking backend (under default settings). This small PR:

- Fixes sprite pixel space point computation for sprites with zero
custom_size
- Resolves issue #19880.

## Solution

We handle the zero custom_size case explicitly and return
`Err(point_relative_to_sprite_center)` instead of
`Ok(point_relative_to_texture)`.

## Testing

Implemented a new test for zero custom_size sprites within the
`bevy_sprite::sprite` module. Also verified that the example from issue
#19880 is behaving as expected.

No further testing is required.

- How can other people (reviewers) test your changes? Is there anything
specific they need to know?

Can run the simple application example from the linked issue. Or
evaluate the implemented test.

---------

Co-authored-by: James Lucas <jalucas@nvidia.com>
2025-07-03 17:43:32 +00:00
Talin
870490808d
Feathers toggle switches. (#19928)
# Objective

This is the Feathers toggle switch widget (without animation).

Part of #19236 

### Showcase

<img width="143" alt="toggles"
src="https://github.com/user-attachments/assets/c04afc06-5a57-4bc6-8181-99efbd1bebef"
/>
2025-07-03 01:09:31 +00:00
Jordan Halase
0adbacd4c2
Set checkbox and radio fill color to gray when disabled in core widgets example (#19792)
Simple color change to the core widgets example. This sets the fill
colors of the elements to gray if they are selected but disabled. It was
hard to notice if they were disabled when they were still green.


![disabled_gray](https://github.com/user-attachments/assets/299f0700-9fab-4aa4-9076-f17859a60a5e)
2025-07-02 23:55:58 +00:00
Greeble
05d954e1ab
Add test that repros #11111 (different loader settings produce same asset) (#19094)
## Objective

Add a test that reproduces #11111 (and partially #18267). The bug is
that asset loader settings are effectively ignored if the same asset is
loaded multiple times with different settings.

## Solution

Add a unit test to `bevy_assets/lib.rs`. The test will be marked as
`#[ignore]` until #11111 is fixed.

```rust
// Load the same asset with different settings.

let handle_1 = load(asset_server, "test.u8", 1);
let handle_2 = load(asset_server, "test.u8", 2);

// Handles should be different.

assert_ne!(handle_1, handle_2);
```

## Concerns

I'm not 100% sure that the current behaviour is actually broken - I
can't see anything in the asset system design docs that explicitly says
different settings should create different asset ids.

UPDATE: Sentiment from issue comments and discord varies between "bug"
and "undesirable consequence of design decisions, alternatives should be
explored". So I've concluded that the test is valid and desirable.

## Testing

```sh
cargo test -p bevy_asset --features multi_threaded

# Or to repro the issue:
cargo test -p bevy_asset --features multi_threaded -- --ignored
```
2025-07-02 22:39:04 +00:00
andriyDev
8098cf21ca
Use RenderStartup in bevy_anti_aliasing. (#19897)
# Objective

- Progress towards #19887.

## Solution

- Rewrite the FromWorld impls to systems that create the pipeline
resources.

## Testing

- Ran the `anti_aliasing` example and it still works.
2025-07-02 22:38:44 +00:00
andriyDev
e70f84536a
Use RenderStartup in bevy_gizmos. (#19898)
# Objective

- Progress towards #19887.

## Solution

- Convert `FromWorld` impls into systems that run in `RenderStartup`.
- Add an ordering constraint to ensure that necessary resources exist.

## Testing

- Ran `2d_gizmos` and `3d_gizmos` examples and it still worked.
2025-07-02 20:38:37 +00:00
robtfm
b79b8133c8
fix skin uniform buffer size (#19888)
# Objective

for `BufferUsages::STORAGE` on webgpu (and maybe other contexts), buffer
sizes must be a multiple of 4. the skin uniform buffer starts at 16384
then increases by 1.5x, which eventually hits a number which isn't

## Solution

`.next_multiple_of(4)`
2025-07-02 20:06:27 +00:00
Greeble
861e778c4c
Add unit structs for each ease function (#18739)
## Objective

Allow users to directly call ease functions rather than going through
the `EaseFunction` struct. This is less verbose and more efficient when
the user doesn't need the data-driven aspects of `EaseFunction`.

## Background

`EaseFunction` is a flexible and data-driven way to apply easing. But
that has a price when a user just wants to call a specific ease
function:

```rust
EaseFunction::SmoothStep.sample(t);
```

This is a bit verbose, but also surprisingly inefficient. It calls the
general `EaseFunction::eval`, which won't be inlined and adds an
unnecessary branch. It can also increase code size since it pulls in all
ease functions even though the user might only require one. As far as I
can tell this is true even with `opt-level = 3` and `lto = "fat"`.

```asm
; EaseFunction::SmoothStep.sample_unchecked(t)
lea rcx, [rip + __unnamed_2] ; Load the disciminant for EaseFunction::SmoothStep.
movaps xmm1, xmm0
jmp bevy_math::curve::easing::EaseFunction::eval    
```

## Solution

This PR adds a struct for each ease function. Most are unit structs, but
a couple have parameters:

```rust
SmoothStep.sample(t);

Elastic(50.0).sample(t);

Steps(4, JumpAt::Start).sample(t)
```

The structs implement the `Curve<f32>` trait. This means they fit into
the broader `Curve` system, and the user can choose between `sample`,
`sample_unchecked`, and `sample_clamped`. The internals are a simple
function call so the compiler can easily estimate the cost of inlining:

```asm
; SmoothStep.sample_unchecked(t)
movaps xmm1, xmm0
addss xmm1, xmm0
movss xmm2, dword ptr [rip + __real@40400000] ; 3.0
subss xmm2, xmm1
mulss xmm2, xmm0
mulss xmm0, xmm2
```

In a microbenchmark this is around 4x faster. If inlining permits
auto-vectorization then it's 20-50x faster, but that's a niche case.

Adding unit structs is also a small boost to discoverability - the unit
struct can be found in VS Code via "Go To Symbol" -> "smoothstep", which
doesn't find `EaseFunction::SmoothStep`.

### Concerns

- While the unit structs have advantages, they add a lot of API surface
area.
- Another option would have been to expose the underlying functions.
  - But functions can't implement the `Curve` trait.
- And the underlying functions are unclamped, which could be a footgun.
- Or there have to be three functions to cover unchecked/checked/clamped
variants.
- The unit structs can't be used with `EasingCurve`, which requires
`EaseFunction`.
  - This might confuse users and limit optimisation.
    -  Wrong: `EasingCurve::new(a, b, SmoothStep)`.
    -  Right: `EasingCurve::new(a, b, EaseFunction::SmoothStep)`.
- In theory `EasingCurve` could be changed to support any `Curve<f32>`
or a more limited trait.
- But that's likely to be a breaking change and raises questions around
reflection and reliability.
- The unit structs don't have serialization.
- I don't know much about the motivations/requirements for
serialization.
- Each unit struct duplicates the documentation of `EaseFunction`.
- This is convenient for the user, but awkward for anyone updating the
code.
- Maybe better if each unit struct points to the matching
`EaseFunction`.
  - Might also make the module page less intimidating (see screenshot).


![image](https://github.com/user-attachments/assets/59d1cf1f-d136-437f-8ad6-fdae8ca7d57a)

## Testing

```
cargo test -p bevy_math
```
2025-07-02 19:18:20 +00:00
charlotte 🌸
18712f31f9
Make render and compute pipeline descriptors defaultable. (#19903)
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.
2025-07-02 18:47:27 +00:00
Nicholas Nethercote
1b4cf02fc8
bevy_reflect: streamline generated FromReflect::from_reflect (#19906)
# Objective

Generated `from_reflect` methods use closures in a weird way, e.g.:
```rust
    x: (|| {
        <f32 as ::bevy::reflect::FromReflect>::from_reflect(
            ::bevy::reflect::Struct::field(__ref_struct, "x")?,
        )   
    })()?,
```
The reason for this is because when `#[reflect(Default)]` is used, you
instead get stuff like this:
```rust
    if let ::core::option::Option::Some(__field) = (|| {
        <f32 as ::bevy::reflect::FromReflect>::from_reflect(
            ::bevy::reflect::Struct::field(__ref_struct, "x")?,
        )   
    })() {
        __this.x = __field;
    } 
```
and the closure is necessary to contain the scope of the `?`. But the
first case is more common.

Helps with #19873.

## Solution

Avoid the closure in the common case.

## Testing

I used cargo expand to confirm the closures are no longer produced in
the common case.

`-Zmacro-stats` output tells me this reduces the size of the `Reflect`
code produced for `bevy_ui` by 0.5%.
2025-07-02 14:59:20 +00:00
andriyDev
f95f42b44a
Allow calling add_render_graph_node on World. (#19912)
# 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.
2025-07-02 14:56:18 +00:00
jf908
c8cdb1197e
Add instructions for GPU debugging in Xcode (#19915)
# Objective

- Using Xcode can be confusing to setup for rust projects.

# Solution

- Add instructions to docs/profiling.md for how to use start debugging a
bevy project with Xcode's GPU debugging/profiling tools.
2025-07-02 14:55:25 +00:00
François Mockers
e42d386625
set required-features for example light_textures & clustered_decals (#19913)
# 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`
2025-07-02 14:54:10 +00:00
Nicholas Nethercote
607f9f24d3
Avoid unnecessary ReflectMeta arguments (#19919)
# Objective

`WhereClauseOption` contains a reference to a `ReflectMeta`. Oddly
enough, a bunch of functions that take a `WhereClauseOption` argument
also take a `ReflectMeta` reference argument, which is exactly the same
as the reference in the `WhereClauseOption`.

## Solution

This commit removes the redundant `ReflectMeta` argument from these
functions. This requires adding a `WhereClauseOption::meta` getter
method.

## Testing

`cargo run -p ci`
2025-07-02 14:53:52 +00:00
Alix Bott
ee1807395e
Implement MapEntities for arrays, HashMap, BTreeMap, IndexMap (#19908)
# Objective

- `MapEntities` is not implemented for arrays, `HashMap`, `BTreeMap`,
and `IndexMap`.

## Solution

- Implement `MapEntities` for arrays, `HashMap`, `BTreeMap`, `IndexMap`

## Testing

- I didn't add a test for this as the implementations seems pretty
trivial
2025-07-02 14:50:55 +00:00
SpecificProtagonist
9e0c66bd65
Ecs derive docs (#19892)
# Objective

Concise syntax docs on `Component`/`Event` derives. Partial fix for
#19537.

## Solution

Only document syntax. The doc tests are set to ignore because the macro
relies on the presence of `bevy_ecs`.
2025-07-02 14:44:18 +00:00
andriyDev
d05c435848
Replace Handle::Weak with Handle::Uuid. (#19896)
# 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!
2025-07-02 14:40:35 +00:00
andriyDev
1a410efd24
Flatten PrepassPipelineInternal into PrepassPipeline. (#19909)
# Objective

- PrepassPipelineInternal used to exist to optimize compile time and
binary size when PrepassPipeline was generic over the material.
- After #19667, PrepassPipeline is no longer generic!

## Solution

- Flatten all the fields of `PrepassPipelineInternal` into
`PrepassPipeline`.
2025-07-01 19:27:42 +00:00
ickshonpe
a949867a1c
UI z-ordering fix (#19691)
# 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.
2025-07-01 19:20:07 +00:00
ickshonpe
5e8aa7986b
Newtyped ScrollPosition (#19881)
# 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>
2025-07-01 17:41:48 +00:00
Talin
b980d4ac22
Feathers checkbox (#19900)
Adds checkbox and radio buttons to feathers.

Showcase:

<img width="378" alt="feathers-checkbox-radio"
src="https://github.com/user-attachments/assets/76d35589-6400-49dd-bf98-aeca2f39a472"
/>
2025-07-01 06:59:14 +00:00