Commit Graph

8239 Commits

Author SHA1 Message Date
Patrick Walton
fc831c390d
Implement basic clustered decal projectors. (#17315)
This commit adds support for *decal projectors* to Bevy, allowing for
textures to be projected on top of geometry. Decal projectors are
clusterable objects, just as punctual lights and light probes are. This
means that decals are only evaluated for objects within the conservative
bounds of the projector, and they don't require a second pass.

These clustered decals require support for bindless textures and as such
currently don't work on WebGL 2, WebGPU, macOS, or iOS. For an
alternative that doesn't require bindless, see PR #16600. I believe that
both contact projective decals in #16600 and clustered decals are
desirable to have in Bevy. Contact projective decals offer broader
hardware and driver support, while clustered decals don't require the
creation of bounding geometry.

A new example, `decal_projectors`, has been added, which demonstrates
multiple decals on a rotating object. The decal projectors can be scaled
and rotated with the mouse.

There are several limitations of this initial patch that can be
addressed in follow-ups:

1. There's no way to specify the Z-index of decals. That is, the order
in which multiple decals are blended on top of one another is arbitrary.
A follow-up could introduce some sort of Z-index field so that artists
can specify that some decals should be blended on top of others.

2. Decals don't take the normal of the surface they're projected onto
into account. Most decal implementations in other engines have a feature
whereby the angle between the decal projector and the normal of the
surface must be within some threshold for the decal to appear. Often,
artists can specify a fade-off range for a smooth transition between
oblique surfaces and aligned surfaces.

3. There's no distance-based fadeoff toward the end of the projector
range. Many decal implementations have this.

This addresses #2401.
 
## Showcase

![Screenshot 2025-01-11
052913](https://github.com/user-attachments/assets/8fabbafc-60fb-461d-b715-d7977e10fe1f)
2025-01-26 20:13:39 +00:00
Predko Silvestr
deb135c25c
Proportional scaling for the sprite's texture. (#17258)
# Objective

Bevy sprite image mode lacks proportional scaling for the underlying
texture. In many cases, it's required. For example, if it is desired to
support a wide variety of screens with a single texture, it's okay to
cut off some portion of the original texture.

## Solution

I added scaling of the texture during the preparation step. To fill the
sprite with the original texture, I scaled UV coordinates accordingly to
the sprite size aspect ratio and texture size aspect ratio. To fit
texture in a sprite the original `quad` is scaled and then the
additional translation is applied to place the scaled quad properly.


## Testing

For testing purposes could be used `2d/sprite_scale.rs`. Also, I am
thinking that it would be nice to have some tests for a
`crates/bevy_sprite/src/render/mod.rs:sprite_scale`.

---

## Showcase

<img width="1392" alt="image"
src="https://github.com/user-attachments/assets/c2c37b96-2493-4717-825f-7810d921b4bc"
/>
2025-01-24 18:24:02 +00:00
Vic
39a1e2b488
implement EntityIndexMap/Set (#17449)
# Objective

We do not have `EntityIndexMap`/`EntityIndexSet`.

Usual `HashMap`s/`HashSet`s do not guarantee any order, which can be
awkward for some use cases.
The `indexmap` versions remember insertion order, which then also
becomes their iteration order.
They can be thought of as a `HashTable` + `Vec`, which means fast
iteration and removal, indexing by index (not just key), and slicing!
Performance should otherwise be comparable.

## Solution

Because `indexmap` is structured to mirror `hashbrown`, it suffers the
same issue of not having the `Hasher` generic on their iterators. #16912
solved this issue for `EntityHashMap`/`EntityHashSet` with a wrapper
around the hashbrown version, so this PR does the same.

Hopefully these wrappers can be removed again in the future by having
`hashbrown`/`indexmap` adopt that generic in their iterators themselves!
2025-01-24 08:09:34 +00:00
spvky
40007cdb2e
Adds update interval config for FpsOverlayPlugin (#17489)
# Objective
Fixes #17487 

- Adds a new field `refresh_interval` to `FpsOverlayConfig` to allow the
user setting a minimum time before each refresh of the FPS display

## Solution

- Add `refresh_interval` to `FpsOverlayConfig`
- When updating the on screen text, check a duration of
`refresh_interval` has passed, if not, don't update the FPS counter

## Testing

- Created a new bevy project
- Included the `FpsOverlayPlugin` with the default `refresh_interval`
(100 ms)
- Included the `FpsOverlayPlugin` with an obnoxious `refresh_interval`
(2 seconds)
---

---------

Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-24 05:57:36 +00:00
Rostyslav Toch
af3a84fc0b
Add many_materials stress test (#17346)
# Objective

- This PR adds a new stress test called `many_materials` to benchmark
the rendering performance of many animated materials.
- Fixes #11588 
- This PR continues the work started in the previous PR #11592, which
was closed due to inactivity.

## Solution

- Created a new example (`examples/stress_tests/many_materials.rs`) that
renders a grid of cubes with animated materials.
- The size of the grid can be configured using the `-n` command-line
argument (or `--grid-size`). The default grid size is 10x10.
- The materials animate by cycling through colors in the HSL color
space.

## Testing

- I have tested these changes locally on my Linux machine.
- Reviewers can test the changes by running the example with different
grid sizes and observing the performance (FPS, frame time).
- I have not tested on other platforms (macOS, Windows, wasm), but I
expect it to work as the code uses standard Bevy features.

---

## Showcase

<details>
  <summary>Click to view showcase</summary>


![image](https://github.com/user-attachments/assets/b15209d4-f832-402b-a527-58e5048971d1)

</details>
2025-01-24 05:46:23 +00:00
Richard Jones
e20ac69cb3
Clarify docs for OnAdd, OnInsert, OnReplace, OnRemove triggers (#17512)
# Objective

- Trouble remembering the difference between `OnAdd` and `OnInsert` for
triggers. Would like a better doc for those triggers so it appears in my
editor tooltip.

## Solution

- Clarify docs for OnAdd, OnInsert, OnRemove, OnReplace. Based on
comments in the
[component_hook.rs](https://github.com/bevyengine/bevy/blob/main/examples/ecs/component_hooks.rs#L73)
example.


## Testing

- None, small doc fix.
2025-01-24 05:40:58 +00:00
Vic
94a238b0ef
implement FromEntitySetIterator (#17513)
# Objective

Some collections are more efficient to construct when we know that every
element is unique in advance.
We have `EntitySetIterator`s from #16547, but currently no API to safely
make use of them this way.

## Solution

Add `FromEntitySetIterator` as a subtrait to `FromIterator`, and
implement it for the `EntityHashSet`/`hashbrown::HashSet` types.
To match the normal `FromIterator`, we also add a
`EntitySetIterator::collect_set` method.
It'd be better if these methods could shadow `from_iter` and `collect`
completely, but https://github.com/rust-lang/rust/issues/89151 is needed
for that.

While currently only `HashSet`s implement this trait, future
`UniqueEntityVec`/`UniqueEntitySlice` functionality comes with more
implementors.

Because `HashMap`s are collected from tuples instead of singular types,
implementing this same optimization for them is more complex, and has to
be done separately.

## Showcase

This is basically a free speedup for collecting `EntityHashSet`s!

```rust
pub fn collect_milk_dippers(dippers: Query<Entity, (With<Milk>, With<Cookies>)>) {
    dippers.iter().collect_set::<EntityHashSet>();
    // or
    EntityHashSet::from_entity_set_iter(dippers);
}

---------

Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net>
2025-01-24 05:39:35 +00:00
mgi388
14ad25227b
Make CustomCursor variants CustomCursorImage/CustomCursorUrl structs (#17518)
# Objective

- Make `CustomCursor::Image` easier to work with by splitting the enum
variants off into `CustomCursorImage` and `CustomCursorUrl` structs and
deriving `Default` on those structs.
- Refs #17276.

## Testing

- Ran two examples: `cargo run --example custom_cursor_image
--features=custom_cursor` and `cargo run --example window_settings
--features=custom_cursor`
- CI.

---

## Migration Guide

The `CustomCursor` enum's variants now hold instances of
`CustomCursorImage` or `CustomCursorUrl`. Update your uses of
`CustomCursor` accordingly.
2025-01-24 05:39:04 +00:00
ickshonpe
e459dd94ec
Replace checks for empty uinodes (#17520)
# Objective

The `is_empty` checks that are meant to stop zero-sized uinodes from
being extracted are missing from `extract_uinode_background_colors`,
`extract_uinode_images` and `extract_ui_material_nodes`.

## Solution

Put them back.
2025-01-24 05:38:20 +00:00
Emerson Coskey
81a25bb0c7
Procedural atmospheric scattering (#16314)
Implement procedural atmospheric scattering from [Sebastien Hillaire's
2020 paper](https://sebh.github.io/publications/egsr2020.pdf). This
approach should scale well even down to mobile hardware, and is
physically accurate.

## Co-author: @mate-h 

He helped massively with getting this over the finish line, ensuring
everything was physically correct, correcting several places where I had
misunderstood or misapplied the paper, and improving the performance in
several places as well. Thanks!

## Credits

@aevyrie: helped find numerous bugs and improve the example to best show
off this feature :)

Built off of @mtsr's original branch, which handled the transmittance
lut (arguably the most important part)

## Showcase: 


![sunset](https://github.com/user-attachments/assets/2eee1f38-f66d-4772-bb72-163e13c719d8)

![twilight](https://github.com/user-attachments/assets/f7d358b6-898d-4df7-becc-188cd753102d)


## For followup

- Integrate with pcwalton's volumetrics code
- refactor/reorganize for better integration with other effects
- have atmosphere transmittance affect directional lights
- add support for generating skybox/environment map

---------

Co-authored-by: Emerson Coskey <56370779+EmersonCoskey@users.noreply.github.com>
Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: Emerson Coskey <coskey@emerlabs.net>
Co-authored-by: Máté Homolya <mate.homolya@gmail.com>
2025-01-23 22:52:46 +00:00
Zachary Harrold
d9ba1af87c
Fix Typo in bevy_platform_support's spin Feature (#17516)
# Objective

- Fix typo in `spin/portable-atomic` feature.

## Solution

- Replace with `spin/portable_atomic`

## Testing

- CI

---

## Notes

This is a very annoying design choice the `spin` developers made.
Because the _crate_ is called `portable-atomic` and is optional, Cargo
automatically registers the feature `portable-atomic`. But the
maintainers use `portable_atomic` for their _feature_ which enables the
support. Sneaks through CI because it's a valid feature and will only
cause breakage on atomically challenged platforms (which we currently
aren't testing in CI).

Should we test atomically challenged in CI? Right now I don't think so,
at least not until we've made "normal" `no_std` CI better with the main
`bevy` crate as the test-case rather than each individual crate.
2025-01-23 21:47:21 +00:00
Radislav Myasnikov
94e0e1f031
Updated the 2D examples to make them uniform (#17237)
# Objective

Make the examples look more uniform and more polished.
following the issue #17167

## Solution

- [x] Added a minimal UI explaining how to interact with the examples
only when needed.
- [x] Used the same notation for interactions ex : "Up Arrow: Move
Forward \nLeft / Right Arrow: Turn"
- [x] Set the color to
[GRAY](https://github.com/bevyengine/bevy/pull/17237#discussion_r1907560092)
when it's not visible enough
- [x] Changed some colors to be easy on the eyes
- [x] removed the //camera comment
- [x] Unified the use of capital letters in the examples.
- [x] Simplified the mesh2d_arc offset calculations.

...

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
2025-01-23 16:46:58 +00:00
Zachary Harrold
9bc0ae33c3
Move hashbrown and foldhash out of bevy_utils (#17460)
# Objective

- Contributes to #16877

## Solution

- Moved `hashbrown`, `foldhash`, and related types out of `bevy_utils`
and into `bevy_platform_support`
- Refactored the above to match the layout of these types in `std`.
- Updated crates as required.

## Testing

- CI

---

## Migration Guide

- The following items were moved out of `bevy_utils` and into
`bevy_platform_support::hash`:
  - `FixedState`
  - `DefaultHasher`
  - `RandomState`
  - `FixedHasher`
  - `Hashed`
  - `PassHash`
  - `PassHasher`
  - `NoOpHash`
- The following items were moved out of `bevy_utils` and into
`bevy_platform_support::collections`:
  - `HashMap`
  - `HashSet`
- `bevy_utils::hashbrown` has been removed. Instead, import from
`bevy_platform_support::collections` _or_ take a dependency on
`hashbrown` directly.
- `bevy_utils::Entry` has been removed. Instead, import from
`bevy_platform_support::collections::hash_map` or
`bevy_platform_support::collections::hash_set` as appropriate.
- All of the above equally apply to `bevy::utils` and
`bevy::platform_support`.

## Notes

- I left `PreHashMap`, `PreHashMapExt`, and `TypeIdMap` in `bevy_utils`
as they might be candidates for micro-crating. They can always be moved
into `bevy_platform_support` at a later date if desired.
2025-01-23 16:46:08 +00:00
Zachary Harrold
04990fcd27
Move spin to bevy_platform_support out of other crates (#17470)
# Objective

- Contributes to #16877

## Solution

- Expanded `bevy_platform_support::sync` module to provide
API-compatible replacements for `std` items such as `RwLock`, `Mutex`,
and `OnceLock`.
- Removed `spin` from all crates except `bevy_platform_support`.

## Testing

- CI

---

## Notes

- The sync primitives, while verbose, entirely rely on `spin` for their
implementation requiring no `unsafe` and not changing the status-quo on
_how_ locks actually work within Bevy. This is just a refactoring to
consolidate the "hacks" and workarounds required to get a consistent
experience when either using `std::sync` or `spin`.
- I have opted to rely on `std::sync` for `std` compatible locks,
maintaining the status quo. However, now that we have these locks
factored out into the own module, it would be trivial to investigate
alternate locking backends, such as `parking_lot`.
- API for these locking types is entirely based on `std`. I have
implemented methods and types which aren't currently in use within Bevy
(e.g., `LazyLock` and `Once`) for the sake of completeness. As the
standard library is highly stable, I don't expect the Bevy and `std`
implementations to drift apart much if at all.

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
2025-01-23 05:27:02 +00:00
ickshonpe
dd2d84b342
Remove ViewVisibility from UI nodes (#17405)
# Objective

The UI can only target a single view and doesn't support `RenderLayers`,
so there doesn't seem to be any need for UI nodes to require
`ViewVisibility` and `VisibilityClass`.

Fixes #17400

## Solution

Remove the `ViewVisibility` and `VisibilityClass` component requires
from `Node` and change the visibility queries to only query for
`InheritedVisibility`.

## Testing

```cargo run --example many_buttons --release --features "trace_tracy"```

Yellow is this PR, red is main.

`bevy_render::view::visibility::reset_view_visibility`
<img width="531" alt="reset-view" src="https://github.com/user-attachments/assets/a44b215d-96bf-43ec-8669-31530ff98eae" />

`bevy_render::view::visibility::check_visibility`
<img width="445" alt="view_visibility" src="https://github.com/user-attachments/assets/fa111757-da91-434d-88e4-80bdfa29374f" />
2025-01-23 05:26:10 +00:00
Sven Niederberger
68c19defb6
Readback: Add support for texture depth/array layers (#17479)
# Objective

Fixes #16963

## Solution

I am - no pun intended - somewhat out of my depth here but this worked
in my testing. The validation error is gone and the data read from the
GPU looks sensible. I'd greatly appreciate if somebody more familiar
with the matter could double-check this.

## References

Relevant documentation in
[WebGPU](https://gpuweb.github.io/gpuweb/#gputexelcopybufferlayout) and
[wgpu](https://github.com/gfx-rs/wgpu/blob/v23/wgpu-types/src/lib.rs#L6350).

## Testing

<details><summary>Example code for testing</summary>
<p>

```rust
use bevy::{
    image::{self as bevy_image, TextureFormatPixelInfo},
    prelude::*,
    render::{
        render_asset::RenderAssetUsages,
        render_resource::{
            Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
        },
    },
};

fn main() {
    let mut app = App::new();
    app.add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, readback_system);
    app.run();
}

#[derive(Resource)]
struct ImageResource(Handle<Image>);

const TEXTURE_HEIGHT: u32 = 64;
const TEXTURE_WIDTH: u32 = 32;
const TEXTURE_LAYERS: u32 = 4;
const FORMAT: TextureFormat = TextureFormat::Rgba8Uint;

fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
    let layer_pixel_count = (TEXTURE_WIDTH * TEXTURE_HEIGHT) as usize;
    let layer_size = layer_pixel_count * FORMAT.pixel_size();
    let data: Vec<u8> = (0..TEXTURE_LAYERS as u8)
        .flat_map(|layer| (0..layer_size).map(move |_| layer))
        .collect();
    let image_size = data.len();
    println!("{image_size}");
    let image = Image {
        data,
        texture_descriptor: TextureDescriptor {
            label: Some("image"),
            size: Extent3d {
                width: TEXTURE_WIDTH,
                height: TEXTURE_HEIGHT,
                depth_or_array_layers: TEXTURE_LAYERS,
            },
            mip_level_count: 1,
            sample_count: 1,
            dimension: TextureDimension::D2,
            format: FORMAT,
            usage: TextureUsages::COPY_DST | TextureUsages::COPY_SRC,
            view_formats: &[],
        },
        sampler: bevy_image::ImageSampler::Default,
        texture_view_descriptor: None,
        asset_usage: RenderAssetUsages::RENDER_WORLD,
    };

    commands.insert_resource(ImageResource(images.add(image)));
}

fn readback_system(
    mut commands: Commands,
    keys: Res<ButtonInput<KeyCode>>,
    image: Res<ImageResource>,
) {
    if !keys.just_pressed(KeyCode::KeyR) {
        return;
    }

    commands
        .spawn(bevy::render::gpu_readback::Readback::Texture(
            image.0.clone(),
        ))
        .observe(
            |trigger: Trigger<bevy::render::gpu_readback::ReadbackComplete>,
             mut commands: Commands| {
                info!("readback complete");

                println!("{:#?}", &trigger.0);

                commands.entity(trigger.observer()).despawn();
            },
        );
}

```

</p>
</details>
2025-01-23 05:25:40 +00:00
Patrick Walton
56aa90240e
Only include distance fog in the PBR shader if the view uses it. (#17495)
Right now, we always include distance fog in the shader, which is
unfortunate as it's complex code and is rare. This commit changes it to
be a `#define` instead. I haven't confirmed that removing distance fog
meaningfully reduces VGPR usage, but it can't hurt.
2025-01-23 05:24:54 +00:00
Rob Parrett
17294eebb2
Update async-broadcast (#17500)
# Objective

Dependabot tried up update this earlier, but it was noticed that this
broke wasm builds. A new release has happened since then which includes
a fix for that.

Here's the
[changelog](https://github.com/smol-rs/async-broadcast/blob/master/CHANGELOG.md).

Closes #11830

## Solution

Use `async-broadcast` `0.7.2`.

## Testing

I ran a few some examples involving assets on macos / wasm.
2025-01-23 05:24:34 +00:00
Zachary Harrold
8e6bf0637b
Add no_std support to bevy_diagnostic (#17507)
# Objective

- Contributes to #15460

## Solution

- Added required features
- Switched from `tracing` to `log`
- Fixed imports

## Testing

- CI
2025-01-23 05:20:34 +00:00
Tim Overbeek
da57dfb62f
DeriveWorld for enums (#17496)
# Objective

Fixes #17457 

## Solution

#[derive(FromWorld)] now works with enums by specifying which variant
should be used.

## Showcase

```rust
#[Derive(FromWorld)]
enum Game {
    #[from_world]
    Playing, 
    Stopped
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
2025-01-23 04:06:00 +00:00
Thierry Berger
fd2afeefda
Mesh::merge to return a Result (#17475)
# Objective

Make `Mesh::merge` more resilient to use.

Currently, it's difficult to make sure `Mesh::merge` will not panic
(we'd have to check if all attributes are compatible).

- I'd appreciate it for utility function to convert different mesh
representations such as:
https://github.com/dimforge/bevy_rapier/pull/628.

## Solution

- Make `Mesh::merge` return a `Result`.

## Testing

- It builds

## Migration Guide

- `Mesh::merge` now returns a `Result<(), MeshMergeError>`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
2025-01-23 04:05:36 +00:00
Zachary Harrold
9387fcfbf2
Add no_std Support to bevy_a11y (#17505)
# Objective

- Contributes to #15460

## Solution

- Add `std` feature gate
- Fixed partially used serialisation and reflection features.

## Testing

- CI
2025-01-23 03:52:47 +00:00
ickshonpe
434bbe6027
flex_basis doc comment fix (#17502)
# Objective

The doc comment for `Node::flex_basis` which refers to a`size` field
that was replaced by individual `width` and `height` fields sometime
ago.

## Solution

Refer to the individual fields instead.
2025-01-23 02:48:01 +00:00
Zachary Harrold
41e79ae826
Refactored ComponentHook Parameters into HookContext (#17503)
# Objective

- Make the function signature for `ComponentHook` less verbose

## Solution

- Refactored `Entity`, `ComponentId`, and `Option<&Location>` into a new
`HookContext` struct.

## Testing

- CI

---

## Migration Guide

Update the function signatures for your component hooks to only take 2
arguments, `world` and `context`. Note that because `HookContext` is
plain data with all members public, you can use de-structuring to
simplify migration.

```rust
// Before
fn my_hook(
    mut world: DeferredWorld,
    entity: Entity,
    component_id: ComponentId,
) { ... }

// After
fn my_hook(
    mut world: DeferredWorld,
    HookContext { entity, component_id, caller }: HookContext,
) { ... }
``` 

Likewise, if you were discarding certain parameters, you can use `..` in
the de-structuring:

```rust
// Before
fn my_hook(
    mut world: DeferredWorld,
    entity: Entity,
    _: ComponentId,
) { ... }

// After
fn my_hook(
    mut world: DeferredWorld,
    HookContext { entity, .. }: HookContext,
) { ... }
```
2025-01-23 02:45:24 +00:00
Zachary Harrold
c7ddec571d
Fix Time (#17504)
# Objective

- Fix issue @mockersf identified with `example-showcase` where time was
not being received correctly from the render world.

## Solution

- Refactored to ensure `TimeReceiver` is always cleared even if it isn't
being used in the main world.

## Testing

- `cargo run -p example-showcase -- --page 1 --per-page 1 run
--screenshot-frame 200 --fixed-frame-time 0.0125 --stop-frame 450
--in-ci --show-logs`
2025-01-23 02:44:16 +00:00
Rob Parrett
784a9d36bd
Add warning for font sizes <= 0.0 (#17501)
# Objective

Alternative to #9660, which is outdated since "required components"
landed.

Fixes #9655

## Solution

This is a different approach than the linked PR, slotting the warning
into an existing check for zero or negative font sizes in the text
pipeline.

## Testing

Replaced a font size with `0.0` in `examples/ui/text.rs`.

```
2025-01-22T23:26:08.239688Z  INFO bevy_winit::system: Creating new window App (0v1)
2025-01-22T23:26:08.617505Z  WARN bevy_text::pipeline: Text span 10v1 has a font size <= 0.0. Nothing will be displayed.
```
2025-01-23 02:43:59 +00:00
Zachary Harrold
d921fdc376
Add no_std Support to bevy_time (#17491)
# Objective

- Contributes to #15460

## Solution

- Switched `tracing` for `log` for the atomically challenged platforms
- Setup feature flags as required
- Added to `compile-check-no-std` CI task
- Made `crossbeam-channel` optional depending on `std`.

## Testing

- CI

---

## Notes

- `crossbeam-channel` provides a MPMC channel type which isn't readily
replicable in `no_std`, and is only used for a `bevy_render`
integration. As such, I've feature-gated the `TimeReceiver` and
`TimeSender` types.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-22 20:02:43 +00:00
SpecificProtagonist
f32a6fb205
Track callsite for observers & hooks (#15607)
# Objective

Fixes #14708

Also fixes some commands not updating tracked location.


## Solution

`ObserverTrigger` has a new `caller` field with the
`track_change_detection` feature;
hooks take an additional caller parameter (which is `Some(…)` or `None`
depending on the feature).

## Testing

See the new tests in `src/observer/mod.rs`

---

## Showcase

Observers now know from where they were triggered (if
`track_change_detection` is enabled):
```rust
world.observe(move |trigger: Trigger<OnAdd, Foo>| {
    println!("Added Foo from {}", trigger.caller());
});
```

## Migration

- hooks now take an additional `Option<&'static Location>` argument

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-22 20:02:39 +00:00
Zachary Harrold
5c43890d49
no_std Support for bevy_input_focus (#17490)
# Objective

- Contributes to #15460

## Solution

- Switched `tracing` for `log` for the atomically challenged platforms
- Setup feature flags as required
- Added to `compile-check-no-std` CI task

## Testing

- CI

---

## Notes

- _Very_ easy one this time. Most of the changes here are just feature
definitions and documentation within the `Cargo.toml`
2025-01-22 19:16:04 +00:00
Alexander Krivács Schrøder
d56536a672
Add reflection to the remaining glam Vec types (#17493)
# Objective

Add reflection support to more `glam` `Vec` types, specifically

* I8Vec2
* I8Vec3
* I8Vec4
* U8Vec2
* U8Vec3
* U8Vec4
* I16Vec2
* I16Vec3
* I16Vec4
* U16Vec2
* U16Vec3
* U16Vec4

I needed to do this because I'm using various of these in my Bevy types,
and due to the orphan rules, I can't make these impls locally.

## Solution

Used `impl_reflect!` like for the existing types.

## Testing

This should not require additional testing, though I have verified that
reflection now works for these types in my own project.
2025-01-22 18:48:34 +00:00
Patrick Walton
72ddac140a
Retain RenderMaterialInstances and RenderMeshMaterialIds from frame to frame. (#16985)
This commit makes Bevy use change detection to only update
`RenderMaterialInstances` and `RenderMeshMaterialIds` when meshes have
been added, changed, or removed. `extract_mesh_materials`, the system
that extracts these, now follows the pattern that
`extract_meshes_for_gpu_building` established.

This improves frame time of `many_cubes` from 3.9ms to approximately
3.1ms, which slightly surpasses the performance of Bevy 0.14.

(Resubmitted from #16878 to clean up history.)

![Screenshot 2024-12-17
182109](https://github.com/user-attachments/assets/dfb26e20-b314-4c67-a59a-dc9623fabb62)

---------

Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-22 03:35:46 +00:00
Luc
93e5e6cb95
fix double comment characters (#17484)
# Objective
- Improve docs by removing duplicate comment characters
- Fixes #17483

## Solution
- Replaced `/// ///` with `///`
2025-01-21 23:24:05 +00:00
JaySpruce
fe24652cc0
Change World::try_despawn and World::try_insert_batch to return Result (#17376)
## Objective

Most `try` methods on `World` return a `Result`, but `try_despawn` and
`try_insert_batch` don't. Since Bevy's error handling is advancing,
these should be brought in line.

## Solution

- Added `TryDespawnError` and `TryInsertBatchError`.
- `try_despawn`, `try_insert_batch`, and `try_insert_batch_if_new` now
return their respective errors.
- Fixed slightly incorrect behavior in `try_insert_batch_with_caller`.
- The method was always meant to continue with the rest of the batch if
an entity was missing, but that only worked after the first entity; if
the first entity was missing, the method would exit early. This has been
resolved.

## Migration Guide
- `World::try_despawn` now returns a `Result` rather than a `bool`.
- `World::try_insert_batch` and `World::try_insert_batch_if_new` now
return a `Result` where they previously returned nothing.
2025-01-21 23:21:32 +00:00
Alice Cecile
44ad3bf62b
Move Resource trait to its own file (#17469)
# Objective

`bevy_ecs`'s `system` module is something of a grab bag, and *very*
large. This is particularly true for the `system_param` module, which is
more than 2k lines long!

While it could be defensible to put `Res` and `ResMut` there (lol no
they're in change_detection.rs, obviously), it doesn't make any sense to
put the `Resource` trait there. This is confusing to navigate (and
painful to work on and review).

## Solution

- Create a root level `bevy_ecs/resource.rs` module to mirror
`bevy_ecs/component.rs`
- move the `Resource` trait to that module
- move the `Resource` derive macro to that module as well (Rust really
likes when you pun on the names of the derive macro and trait and put
them in the same path)
- fix all of the imports

## Notes to reviewers

- We could probably move more stuff into here, but I wanted to keep this
PR as small as possible given the absurd level of import changes.
- This PR is ground work for my upcoming attempts to store resource data
on components (resources-as-entities). Splitting this code out will make
the work and review a bit easier, and is the sort of overdue refactor
that's good to do as part of more meaningful work.

## Testing

cargo build works!

## Migration Guide

`bevy_ecs::system::Resource` has been moved to
`bevy_ecs::resource::Resource`.
2025-01-21 19:47:08 +00:00
Alice Cecile
85eceb022d
Add insert and remove recursive methods on EntityWorldMut and EntityCommands (#17463)
# Objective

While being able to quickly add / remove components down a tree is
broadly useful (material changing!), it's particularly necessary when
combined with the newly added #13120.

## Solution

Write four methods: covering both adding and removal on both
`EntityWorldMut` and `EntityCommands`.

These methods are generic over the `RelationshipTarget`, thanks to the
freshly merged relations 🎉

## Testing

I've added a simple unit test for these methods.

---------

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2025-01-21 02:57:57 +00:00
AlephCubed
42b928b90e
Added helper methods to Bundles. (#17464)
Added `len`, `is_empty`, and `iter` methods to `Bundles`.

Separated out from #17331.

---------

Co-authored-by: shuo <shuoli84@gmail.com>
2025-01-21 02:19:02 +00:00
Alice Cecile
b34833f00c
Add an example teaching users about custom relationships (#17443)
# Objective

After #17398, Bevy now has relations! We don't teach users how to make /
work with these in the examples yet though, but we definitely should.

## Solution

- Add a simple abstract example that goes over defining, spawning,
traversing and removing a custom relations.
- ~~Add `Relationship` and `RelationshipTarget` to the prelude: the
trait methods are really helpful here.~~
- this causes subtle ambiguities with method names and weird compiler
errors. Not doing it here!
- Clean up related documentation that I referenced when writing this
example.

## Testing

`cargo run --example relationships`

## Notes to reviewers

1. Yes, I know that the cycle detection code could be more efficient. I
decided to reduce the caching to avoid distracting from the broader
point of "here's how you traverse relationships".
2. Instead of using an `App`, I've decide to use
`World::run_system_once` + system functions defined inside of `main` to
do something closer to literate programming.

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com>
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2025-01-20 23:17:38 +00:00
Carter Anderson
ba5e71f53d
Parent -> ChildOf (#17427)
Fixes #17412

## Objective

`Parent` uses the "has a X" naming convention. There is increasing
sentiment that we should use the "is a X" naming convention for
relationships (following #17398). This leaves `Children` as-is because
there is prevailing sentiment that `Children` is clearer than `ParentOf`
in many cases (especially when treating it like a collection).

This renames `Parent` to `ChildOf`.

This is just the implementation PR. To discuss the path forward, do so
in #17412.

## Migration Guide

- The `Parent` component has been renamed to `ChildOf`.
2025-01-20 22:13:29 +00:00
Andreas Monitzer
000c362de0
Include ReflectFromReflect in all dynamic data types. (#17453)
# Objective

Fixes #17416

## Solution

I just included ReflectFromReflect in all macros and implementations. I
think this should be ok, at least it compiles properly and does fix the
errors in my test code.

## Testing

I generated a DynamicMap and tried to convert it into a concrete
`HashMap` as a `Box<dyn Reflect>`. Without my fix, it doesn't work,
because this line panics:

```rust
let rfr = ty.data::<ReflectFromReflect>().unwrap();
```

where `ty` is the `TypeRegistration` for the (matching) `HashMap`.

I don't know why `ReflectFromReflect` wasn't included everywhere, I
assume that it was an oversight and not an architecture decision I'm not
aware of.

# Migration Guide

The hasher in reflected `HashMap`s and `HashSet`s now have to implement
`Default`. This is the case for the ones provided by Bevy already, and
is generally a sensible thing to do.
2025-01-20 22:08:24 +00:00
NiseVoid
de5486725d
Add DefaultQueryFilters (#13120)
# Objective

Some usecases in the ecosystems are blocked by the inability to stop
bevy internals and third party plugins from touching their entities.
However the specifics of a general purpose entity disabling system are
controversial and further complicated by hierarchies. We can partially
unblock these usecases with an opt-in approach: default query filters.

## Solution

- Introduce DefaultQueryFilters, these filters are automatically applied
to queries that don't otherwise mention the filtered component.
- End users and third party plugins can register default filters and are
responsible for handling entities they have hidden this way.
- Extra features can be left for after user feedback
- The default value could later include official ways to hide entities

---

## Changelog

- Add DefaultQueryFilters
2025-01-20 21:57:39 +00:00
SpecificProtagonist
a7051a4815
Diagnostics for label traits (#17441)
# Objective

Diagnostics for labels don't suggest how to best implement them.
```
error[E0277]: the trait bound `Label: ScheduleLabel` is not satisfied
   --> src/main.rs:15:35
    |
15  |     let mut sched = Schedule::new(Label);
    |                     ------------- ^^^^^ the trait `ScheduleLabel` is not implemented for `Label`
    |                     |
    |                     required by a bound introduced by this call
    |
    = help: the trait `ScheduleLabel` is implemented for `Interned<(dyn ScheduleLabel + 'static)>`
note: required by a bound in `bevy_ecs::schedule::Schedule::new`
   --> /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/schedule/schedule.rs:297:28
    |
297 |     pub fn new(label: impl ScheduleLabel) -> Self {
    |                            ^^^^^^^^^^^^^ required by this bound in `Schedule::new`
```

## Solution

`diagnostics::on_unimplemented` and `diagnostics::do_not_recommend`

## Showcase

New error message:
```
error[E0277]: the trait bound `Label: ScheduleLabel` is not satisfied
   --> src/main.rs:15:35
    |
15  |     let mut sched = Schedule::new(Label);
    |                     ------------- ^^^^^ the trait `ScheduleLabel` is not implemented for `Label`
    |                     |
    |                     required by a bound introduced by this call
    |
    = note: consider annotating `Label` with `#[derive(ScheduleLabel)]`
note: required by a bound in `bevy_ecs::schedule::Schedule::new`
   --> /home/vj/workspace/rust/bevy/crates/bevy_ecs/src/schedule/schedule.rs:297:28
    |
297 |     pub fn new(label: impl ScheduleLabel) -> Self {
    |                            ^^^^^^^^^^^^^ required by this bound in `Schedule::new`
```
2025-01-20 21:51:26 +00:00
Younes
ebbd961739
docs: enhance documentation in query.rs to clarify borrowing rules (#17370)
docs: enhance documentation in `query.rs` to clarify borrowing rules.

Please, let me know if you don't agree with the wording.. There is
always room for improvement.

Tested locally and it looks like this:


![image](https://github.com/user-attachments/assets/1283fcac-c5f7-426f-844f-fc2a12ce2b42)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-20 21:31:20 +00:00
Hexroll by Pen, Dice & Paper
15facbb964
Fixing ui antialiasing clamp call parameters order (#14970) (#17456)
# Objective

Fixes #14970

## Solution

It seems the clamp call in `ui.wgsl` had the parameters order incorrect.

## Testing

Tested using examples/ui in native and my current project in wasm - both
in linux.
Could use some help with testing in other platforms.

---
2025-01-20 21:31:20 +00:00
Thierry Berger
6fc965ed56
Expose a few primitive builders, which seemed to be missed? (#17454)
Some primitives seems to have their export being missed, we can see in
the documentation that types are not followable: :
[CuboidMeshBuilder](https://docs.rs/bevy/latest/bevy/math/prelude/struct.Cuboid.html#impl-Meshable-for-Cuboid)
is not exposed.

This Pr addresses this, + its surrounding modules which were around.
2025-01-20 21:29:38 +00:00
Vic
59657ed1e2
remove unsound DerefMut impls from EntityHashMap/EntityHashSet (#17450)
# Objective

Noticed while doing #17449, I had left these `DerefMut` impls in.
Obtaining mutable references to those inner iterator types allows for
`mem::swap`, which can be used to swap an incorrectly behaving instance
into the wrappers.

## Solution

Remove them!
2025-01-20 21:28:28 +00:00
Alice Cecile
5a9bc28502
Support non-Vec data structures in relations (#17447)
# Objective

The existing `RelationshipSourceCollection` uses `Vec` as the only
possible backing for our relationships. While a reasonable choice,
benchmarking use cases might reveal that a different data type is better
or faster.

For example:

- Not all relationships require a stable ordering between the
relationship sources (i.e. children). In cases where we a) have many
such relations and b) don't care about the ordering between them, a hash
set is likely a better datastructure than a `Vec`.
- The number of children-like entities may be small on average, and a
`smallvec` may be faster

## Solution

- Implement `RelationshipSourceCollection` for `EntityHashSet`, our
custom entity-optimized `HashSet`.
-~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things
compile.~~
   -  This implementation was cursed and very surprising.
- Instead, by moving the iterator type on `RelationshipSourceCollection`
from an erased RPTIT to an explicit associated type we can add a trait
bound on the offending methods!
- Implement `RelationshipSourceCollection` for `SmallVec`

## Testing

I've added a pair of new tests to make sure this pattern compiles
successfully in practice!

## Migration Guide

`EntityHashSet` and `EntityHashMap` are no longer re-exported in
`bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s
`prelude`, you can access them through their now-public modules,
`hash_set` and `hash_map` instead.

## Notes to reviewers

The `EntityHashSet::Iter` type needs to be public for this impl to be
allowed. I initially renamed it to something that wasn't ambiguous and
re-exported it, but as @Victoronz pointed out, that was somewhat
unidiomatic.

In
1a8564898f,
I instead made the `entity_hash_set` public (and its `entity_hash_set`)
sister public, and removed the re-export. I prefer this design (give me
module docs please), but it leads to a lot of churn in this PR.

Let me know which you'd prefer, and if you'd like me to split that
change out into its own micro PR.
2025-01-20 21:26:08 +00:00
Chris Biscardi
1dd30a620a
Add docs to custom vertex attribute example (#17422)
# Objective

The gltf-json crate seems like it strips/adds an `_` when doing the name
comparison for custom vertex attributes.

* gltf-json
[add](88e719d5de/gltf-json/src/mesh.rs (L341))
* gltf-json
[strip](88e719d5de/gltf-json/src/mesh.rs (L298C12-L298C42))
* [bevy's
handling](b66c3ceb0e/crates/bevy_gltf/src/vertex_attributes.rs (L273-L276))
seems like it uses the non-underscore'd version.

The bevy example gltf:
[barycentric.gltf](b66c3ceb0e/assets/models/barycentric/barycentric.gltf),
includes two underscores: `__BARYCENTRIC` in the gltf file, resulting in
needing `_BARYCENTRIC` (one underscore) as the attribute name in Bevy.
This extra underscore is redundant and does not appear if exporting from
blender, which only requires a single underscore to trigger the
attribute export.

I'm not sure if we want to change the example itself (maybe there's a
reason it has two underscores, I couldn't find a reason), but a docs
comment would help.

## Solution

add docs detailing the behavior
2025-01-20 21:16:11 +00:00
Greeble
b2f3248432
Make the animated_mesh example more intuitive (#17421)
# Objective

Make the `animated_mesh` example more intuitive and easier for the user
to extend.

# Solution

The `animated_mesh` example shows how to spawn a single mesh and play a
single animation. The original code is roughly:

1. In `setup_mesh_and_animation`, spawn an entity with a SceneRoot that
will load and spawn the mesh. Also record the animation to play as a
resource.
2. Use `play_animation_once_loaded` to detect when any animation players
are spawned, then play the animation from the resource.

When I used this example as a starting point for my own app, I hit a
wall when trying to spawn multiple meshes with different animations.
`play_animation_once_loaded` tells me an animation player spawned
somewhere, but how do I get from there to the right animation? The
entity it runs on is spawned by the scene so I can't attach any data to
it?

The new code takes a different approach. Instead of a global resource,
the animation is recorded as a component on the entity with the
SceneRoot. Instead of detecting animation players spawning wherever, an
observer is attached to that specific entity.

This feels more intuitive and localised, and I think most users will
work out how to get from there to different animations and meshes. The
downside is more lines of code, and the "find the animation players"
part still feels a bit magical and inefficient.

# Side Notes

- The solution was mostly stolen from
https://github.com/bevyengine/bevy/issues/14852#issuecomment-2481401769.
- The example still feels too complicated.
    - "Why do I have to make this graph to play one animation?"
- "Why can't I choose and play the animation in one step and avoid this
temporary component?"
    - I think this requires engine changes.
- I originally started on a separate example of multiple meshes
([branch](https://github.com/bevyengine/bevy/compare/main...greeble-dev:bevy:animated-mesh-multiple)).
- I decided that the user could probably work this out themselves from
the single animation example.
    - But maybe still worth following through.

# Testing

`cargo run --example animated_mesh`

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
2025-01-20 21:12:06 +00:00
ickshonpe
3f99a3e8cd
Text 2d alignment fix (#17365)
# Objective

`Text2d` ignores `TextBounds` when calculating the offset for text
aligment.
On main a text entity positioned in the center of the window with center
justification and 600px horizontal text bounds isn't centered like it
should be but shifted off to the right:
<img width="305" alt="hellox"
src="https://github.com/user-attachments/assets/8896c6f0-1b9f-4633-9c12-1de6eff5f3e1"
/>
(second example in the testing section below)

Fixes #14266

I already had a PR in review for this (#14270) but it used post layout
adjustment (which we want to avoid) and ignored `TextBounds`.

## Solution

* If `TextBounds` are present for an axis, use them instead of the size
of the computed text layout size to calculate the offset.
* Adjust the vertical offset of text so it's top is aligned with the top
of the texts bounding rect (when present).

## Testing

```
use bevy::prelude::*;
use bevy::color::palettes;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn example(commands: &mut Commands, dest: Vec3, justify: JustifyText) {
    commands.spawn((
        Sprite {
            color: palettes::css::YELLOW.into(),
            custom_size: Some(10. * Vec2::ONE),
            anchor: Anchor::Center,
            ..Default::default()
        },
        Transform::from_translation(dest),
    ));

    for a in [
        Anchor::TopLeft,
        Anchor::TopRight,
        Anchor::BottomRight,
        Anchor::BottomLeft,
    ] {
        commands.spawn((
            Text2d(format!("L R\n{:?}\n{:?}", a, justify)),
            TextFont {
                font_size: 14.0,
                ..default()
            },
            TextLayout {
                justify,
                ..Default::default()
            },
            TextBounds::new(300., 75.),
            Transform::from_translation(dest + Vec3::Z),
            a,
        ));
    }
}

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d::default());

    for (i, j) in [
        JustifyText::Left,
        JustifyText::Right,
        JustifyText::Center,
        JustifyText::Justified,
    ]
    .into_iter()
    .enumerate()
    {
        example(&mut commands, (300. - 150. * i as f32) * Vec3::Y, j);
    }

    commands.spawn(Sprite {
        color: palettes::css::YELLOW.into(),
        custom_size: Some(10. * Vec2::ONE),
        anchor: Anchor::Center,
        ..Default::default()
    });
}
```

<img width="566" alt="cap"
src="https://github.com/user-attachments/assets/e6a98fa5-80b2-4380-a9b7-155bb49635b8"
/>

This probably looks really confusing but it should make sense if you
imagine each block of text surrounded by a 300x75 rectangle that is
anchored to the center of the yellow square.

# 

```
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d::default());

    commands.spawn((
        Text2d::new("hello"),
        TextFont {
            font_size: 60.0,
            ..default()
        },
        TextLayout::new_with_justify(JustifyText::Center),
        TextBounds::new(600., 200.),
        Anchor::Center,
    ));
}
```

<img width="338" alt="hello"
src="https://github.com/user-attachments/assets/e5e89364-afda-4baa-aca8-df4cdacbb4ed"
/>

The text being above the center is intended. When `TextBounds` are
present, the text block's offset is calculated using its `TextBounds`
not the layout size returned by cosmic-text.

# 

Probably we should add a vertical alignment setting for Text2d. Didn't
do it here as this is intended for a 0.15.2 release.
2025-01-20 20:54:32 +00:00
Emerson Coskey
a99674ab86
FromWorld derive macro (#17352)
simple derive macro for `FromWorld`. Going to be needed for composable
pipeline specializers but probably a nice thing to have regardless

## Testing

simple manual testing, nothing seemed to blow up. I'm no proc macro pro
though, so there's a chance I've mishandled spans somewhere or
something.
2025-01-20 20:51:30 +00:00