Commit Graph

900 Commits

Author SHA1 Message Date
sam edelsten
7935c7e95f
Update picking docs to include position space (#17859)
# Objective

Add reference to reported position space in picking backend docs.

Fixes #17844 

## Solution

Add explanatory docs to the implementation notes of each picking
backend.

## Testing

`cargo r -p ci -- doc-check` & `cargo r -p ci -- lints`
2025-02-15 19:08:12 +00:00
ickshonpe
5ec59cf0b9
Add NodeImageMode to the UI prelude (#17848)
# Objective

Add `NodeImageMode` to `bevy_ui::prelude`.
2025-02-13 19:48:45 +00:00
ickshonpe
98dcee2853
UI text extraction refactor (#17805)
## Objective

There's no need for the `span_index` and `color` variables in
`extract_text_shadows` and `extract_text_sections` and we can remove one
of the span index comparisons since text colors are only set per
section.

## Testing

<img width="454" alt="trace"
src="https://github.com/user-attachments/assets/3109d1df-0817-46c2-9889-0459ac93a42c"
/>
2025-02-11 22:18:47 +00:00
sam edelsten
5eff6e80e1
Add relative position reporting to UI picking (#17681)
# Objective

Add position reporting to `HitData` sent from the UI picking backend.

## Solution

Add the computed normalized relative cursor position to `hit_data`
alongside the `Entity`.

The position reported in `HitData` is normalized relative to the node,
with `(0.,0.,0.)` at the top left and `(1., 1., 0.)` in the bottom
right. Coordinates are relative to the entire node, not just the visible
region.

`HitData` needs a `Vec3` so I just extended with 0.0. I considered
inserting the `depth` here but thought it would be redundant.

I also considered putting the screen space position in the `normal`
field of `HitData`, but that would require renaming of the field or a
separate data structure.

## Testing

Tested with mouse on X11 with entities that have `Node` components.

---

## Showcase

```rs
// Get click position relative to node
fn hit_position(trigger: Trigger<Pointer<Click>>) {
    let hit_pos = trigger.event.hit.position.expect("no position");
    info!("{}", hit_pos);
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-02-11 18:38:13 +00:00
ickshonpe
359cd432c0
UI clipping update function comments fix (#17785)
# Objective
Fix for the comments for the clipping rects update function which
references `Overflow` variants that no longer exist.
2025-02-10 22:35:12 +00:00
ickshonpe
300fe4db4d
Store UI render target info locally per node (#17579)
# Objective

It's difficult to understand or make changes to the UI systems because
of how each system needs to individually track changes to scale factor,
windows and camera targets in local hashmaps, particularly for new
contributors. Any major change inevitably introduces new scale factor
bugs.

Instead of per-system resolution we can resolve the camera target info
for all UI nodes in a system at the start of `PostUpdate` and then store
it per-node in components that can be queried with change detection.

Fixes #17578
Fixes #15143

## Solution

Store the UI render target's data locally per node in a component that
is updated in `PostUpdate` before any other UI systems run.

This component can be then be queried with change detection so that UI
systems no longer need to have knowledge of cameras and windows and
don't require fragile custom change detection solutions using local
hashmaps.

## Showcase
Compare `measure_text_system` from main (which has a bug the causes it
to use the wrong scale factor when a node's camera target changes):
```
pub fn measure_text_system(
    mut scale_factors_buffer: Local<EntityHashMap<f32>>,
    mut last_scale_factors: Local<EntityHashMap<f32>>,
    fonts: Res<Assets<Font>>,
    camera_query: Query<(Entity, &Camera)>,
    default_ui_camera: DefaultUiCamera,
    ui_scale: Res<UiScale>,
    mut text_query: Query<
        (
            Entity,
            Ref<TextLayout>,
            &mut ContentSize,
            &mut TextNodeFlags,
            &mut ComputedTextBlock,
            Option<&UiTargetCamera>,
        ),
        With<Node>,
    >,
    mut text_reader: TextUiReader,
    mut text_pipeline: ResMut<TextPipeline>,
    mut font_system: ResMut<CosmicFontSystem>,
) {
    scale_factors_buffer.clear();

    let default_camera_entity = default_ui_camera.get();

    for (entity, block, content_size, text_flags, computed, maybe_camera) in &mut text_query {
        let Some(camera_entity) = maybe_camera
            .map(UiTargetCamera::entity)
            .or(default_camera_entity)
        else {
            continue;
        };
        let scale_factor = match scale_factors_buffer.entry(camera_entity) {
            Entry::Occupied(entry) => *entry.get(),
            Entry::Vacant(entry) => *entry.insert(
                camera_query
                    .get(camera_entity)
                    .ok()
                    .and_then(|(_, c)| c.target_scaling_factor())
                    .unwrap_or(1.0)
                    * ui_scale.0,
            ),
        };

        if last_scale_factors.get(&camera_entity) != Some(&scale_factor)
            || computed.needs_rerender()
            || text_flags.needs_measure_fn
            || content_size.is_added()
        {
            create_text_measure(
                entity,
                &fonts,
                scale_factor.into(),
                text_reader.iter(entity),
                block,
                &mut text_pipeline,
                content_size,
                text_flags,
                computed,
                &mut font_system,
            );
        }
    }
    core::mem::swap(&mut *last_scale_factors, &mut *scale_factors_buffer);
}
```

with `measure_text_system` from this PR (which always uses the correct
scale factor):
```
pub fn measure_text_system(
    fonts: Res<Assets<Font>>,
    mut text_query: Query<
        (
            Entity,
            Ref<TextLayout>,
            &mut ContentSize,
            &mut TextNodeFlags,
            &mut ComputedTextBlock,
            Ref<ComputedNodeTarget>,
        ),
        With<Node>,
    >,
    mut text_reader: TextUiReader,
    mut text_pipeline: ResMut<TextPipeline>,
    mut font_system: ResMut<CosmicFontSystem>,
) {
    for (entity, block, content_size, text_flags, computed, computed_target) in &mut text_query {
        // Note: the ComputedTextBlock::needs_rerender bool is cleared in create_text_measure().
        if computed_target.is_changed()
            || computed.needs_rerender()
            || text_flags.needs_measure_fn
            || content_size.is_added()
        {
            create_text_measure(
                entity,
                &fonts,
                computed_target.scale_factor.into(),
                text_reader.iter(entity),
                block,
                &mut text_pipeline,
                content_size,
                text_flags,
                computed,
                &mut font_system,
            );
        }
    }
}
```

## Testing

I removed an alarming number of tests from the `layout` module but they
were mostly to do with the deleted camera synchronisation logic. The
remaining tests should all pass now.

The most relevant examples are `multiple_windows` and `split_screen`,
the behaviour of both should be unchanged from main.

---------

Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-02-10 07:27:58 +00:00
Carter Anderson
ea578415e1
Improved Spawn APIs and Bundle Effects (#17521)
## Objective

A major critique of Bevy at the moment is how boilerplatey it is to
compose (and read) entity hierarchies:

```rust
commands
    .spawn(Foo)
    .with_children(|p| {
        p.spawn(Bar).with_children(|p| {
            p.spawn(Baz);
        });
        p.spawn(Bar).with_children(|p| {
            p.spawn(Baz);
        });
    });
```

There is also currently no good way to statically define and return an
entity hierarchy from a function. Instead, people often do this
"internally" with a Commands function that returns nothing, making it
impossible to spawn the hierarchy in other cases (direct World spawns,
ChildSpawner, etc).

Additionally, because this style of API results in creating the
hierarchy bits _after_ the initial spawn of a bundle, it causes ECS
archetype changes (and often expensive table moves).

Because children are initialized after the fact, we also can't count
them to pre-allocate space. This means each time a child inserts itself,
it has a high chance of overflowing the currently allocated capacity in
the `RelationshipTarget` collection, causing literal worst-case
reallocations.

We can do better!

## Solution

The Bundle trait has been extended to support an optional
`BundleEffect`. This is applied directly to World immediately _after_
the Bundle has fully inserted. Note that this is
[intentionally](https://github.com/bevyengine/bevy/discussions/16920)
_not done via a deferred Command_, which would require repeatedly
copying each remaining subtree of the hierarchy to a new command as we
walk down the tree (_not_ good performance).

This allows us to implement the new `SpawnRelated` trait for all
`RelationshipTarget` impls, which looks like this in practice:

```rust
world.spawn((
    Foo,
    Children::spawn((
        Spawn((
            Bar,
            Children::spawn(Spawn(Baz)),
        )),
        Spawn((
            Bar,
            Children::spawn(Spawn(Baz)),
        )),
    ))
))
```

`Children::spawn` returns `SpawnRelatedBundle<Children, L:
SpawnableList>`, which is a `Bundle` that inserts `Children`
(preallocated to the size of the `SpawnableList::size_hint()`).
`Spawn<B: Bundle>(pub B)` implements `SpawnableList` with a size of 1.
`SpawnableList` is also implemented for tuples of `SpawnableList` (same
general pattern as the Bundle impl).

There are currently three built-in `SpawnableList` implementations:

```rust
world.spawn((
    Foo,
    Children::spawn((
        Spawn(Name::new("Child1")),   
        SpawnIter(["Child2", "Child3"].into_iter().map(Name::new),
        SpawnWith(|parent: &mut ChildSpawner| {
            parent.spawn(Name::new("Child4"));
            parent.spawn(Name::new("Child5"));
        })
    )),
))
```

We get the benefits of "structured init", but we have nice flexibility
where it is required!

Some readers' first instinct might be to try to remove the need for the
`Spawn` wrapper. This is impossible in the Rust type system, as a tuple
of "child Bundles to be spawned" and a "tuple of Components to be added
via a single Bundle" is ambiguous in the Rust type system. There are two
ways to resolve that ambiguity:

1. By adding support for variadics to the Rust type system (removing the
need for nested bundles). This is out of scope for this PR :)
2. Using wrapper types to resolve the ambiguity (this is what I did in
this PR).

For the single-entity spawn cases, `Children::spawn_one` does also
exist, which removes the need for the wrapper:

```rust
world.spawn((
    Foo,
    Children::spawn_one(Bar),
))
```

## This works for all Relationships

This API isn't just for `Children` / `ChildOf` relationships. It works
for any relationship type, and they can be mixed and matched!

```rust
world.spawn((
    Foo,
    Observers::spawn((
        Spawn(Observer::new(|trigger: Trigger<FuseLit>| {})),
        Spawn(Observer::new(|trigger: Trigger<Exploded>| {})),
    )),
    OwnerOf::spawn(Spawn(Bar))
    Children::spawn(Spawn(Baz))
))
```

## Macros

While `Spawn` is necessary to satisfy the type system, we _can_ remove
the need to express it via macros. The example above can be expressed
more succinctly using the new `children![X]` macro, which internally
produces `Children::spawn(Spawn(X))`:

```rust
world.spawn((
    Foo,
    children![
        (
            Bar,
            children![Baz],
        ),
        (
            Bar,
            children![Baz],
        ),
    ]
))
```

There is also a `related!` macro, which is a generic version of the
`children!` macro that supports any relationship type:

```rust
world.spawn((
    Foo,
    related!(Children[
        (
            Bar,
            related!(Children[Baz]),
        ),
        (
            Bar,
            related!(Children[Baz]),
        ),
    ])
))
```

## Returning Hierarchies from Functions

Thanks to these changes, the following pattern is now possible:

```rust
fn button(text: &str, color: Color) -> impl Bundle {
    (
        Node {
            width: Val::Px(300.),
            height: Val::Px(100.),
            ..default()
        },
        BackgroundColor(color),
        children![
            Text::new(text),
        ]
    )
}

fn ui() -> impl Bundle {
    (
        Node {
            width: Val::Percent(100.0),
            height: Val::Percent(100.0),
            ..default(),
        },
        children![
            button("hello", BLUE),
            button("world", RED),
        ]
    )
}

// spawn from a system
fn system(mut commands: Commands) {
    commands.spawn(ui());
}

// spawn directly on World
world.spawn(ui());
```

## Additional Changes and Notes

* `Bundle::from_components` has been split out into
`BundleFromComponents::from_components`, enabling us to implement
`Bundle` for types that cannot be "taken" from the ECS (such as the new
`SpawnRelatedBundle`).
* The `NoBundleEffect` trait (which implements `BundleEffect`) is
implemented for empty tuples (and tuples of empty tuples), which allows
us to constrain APIs to only accept bundles that do not have effects.
This is critical because the current batch spawn APIs cannot efficiently
apply BundleEffects in their current form (as doing so in-place could
invalidate the cached raw pointers). We could consider allocating a
buffer of the effects to be applied later, but that does have
performance implications that could offset the balance and value of the
batched APIs (and would likely require some refactors to the underlying
code). I've decided to be conservative here. We can consider relaxing
that requirement on those APIs later, but that should be done in a
followup imo.
* I've ported a few examples to illustrate real-world usage. I think in
a followup we should port all examples to the `children!` form whenever
possible (and for cases that require things like SpawnIter, use the raw
APIs).
* Some may ask "why not use the `Relationship` to spawn (ex:
`ChildOf::spawn(Foo)`) instead of the `RelationshipTarget` (ex:
`Children::spawn(Spawn(Foo))`)?". That _would_ allow us to remove the
`Spawn` wrapper. I've explicitly chosen to disallow this pattern.
`Bundle::Effect` has the ability to create _significant_ weirdness.
Things in `Bundle` position look like components. For example
`world.spawn((Foo, ChildOf::spawn(Bar)))` _looks and reads_ like Foo is
a child of Bar. `ChildOf` is in Foo's "component position" but it is not
a component on Foo. This is a huge problem. Now that `Bundle::Effect`
exists, we should be _very_ principled about keeping the "weird and
unintuitive behavior" to a minimum. Things that read like components
_should be the components they appear to be".

## Remaining Work

* The macros are currently trivially implemented using macro_rules and
are currently limited to the max tuple length. They will require a
proc_macro implementation to work around the tuple length limit.

## Next Steps

* Port the remaining examples to use `children!` where possible and raw
`Spawn` / `SpawnIter` / `SpawnWith` where the flexibility of the raw API
is required.

## Migration Guide

Existing spawn patterns will continue to work as expected.

Manual Bundle implementations now require a `BundleEffect` associated
type. Exisiting bundles would have no bundle effect, so use `()`.
Additionally `Bundle::from_components` has been moved to the new
`BundleFromComponents` trait.

```rust
// Before
unsafe impl Bundle for X {
    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self {
    }
    /* remaining bundle impl here */
}

// After
unsafe impl Bundle for X {
    type Effect = ();
    /* remaining bundle impl here */
}

unsafe impl BundleFromComponents for X {
    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self {
    }
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: Emerson Coskey <emerson@coskey.dev>
2025-02-09 23:32:56 +00:00
François Mockers
7400e7adfd
Cleanup publish process (#17728)
# Objective

- publish script copy the license files to all subcrates, meaning that
all publish are dirty. this breaks git verification of crates
- the order and list of crates to publish is manually maintained,
leading to error. cargo 1.84 is more strict and the list is currently
wrong

## Solution

- duplicate all the licenses to all crates and remove the
`--allow-dirty` flag
- instead of a manual list of crates, get it from `cargo package
--workspace`
- remove the `--no-verify` flag to... verify more things?
2025-02-09 17:46:19 +00:00
ickshonpe
6ed3c3274f
Missing UI glpyhs fix (#17729)
# Objective

Fixes #17718

## Solution

Schedule `text_system` before `AssetEvents`.

I guess what was happening here is that glyphs weren't shown because
`text_system` was running before `AssetEevents` and so `prepare_uinodes`
never recieves the the asset modified event about the glyph texture
atlas image.
2025-02-07 19:41:18 +00:00
Sludge
989f547080
Weak handle migration (#17695)
# Objective

- Make use of the new `weak_handle!` macro added in
https://github.com/bevyengine/bevy/pull/17384

## Solution

- Migrate bevy from `Handle::weak_from_u128` to the new `weak_handle!`
macro that takes a random UUID
- Deprecate `Handle::weak_from_u128`, since there are no remaining use
cases that can't also be addressed by constructing the type manually

## Testing

- `cargo run -p ci -- test`

---

## Migration Guide

Replace `Handle::weak_from_u128` with `weak_handle!` and a random UUID.
2025-02-05 22:44:20 +00:00
ickshonpe
03ec6441a7
Basic UI text shadows (#17559)
# Objective

Basic `TextShadow` support. 

## Solution

New `TextShadow` component with `offset` and `color` fields. Just insert
it on a `Text` node to add a shadow.
New system `extract_text_shadows` handles rendering.

It's not "real" shadows just the text redrawn with an offset and a
different colour. Blur-radius support will need changes to the shaders
and be a lot more complicated, whereas this still looks okay and took a
couple of minutes to implement.

I added the `TextShadow` component to `bevy_ui` rather than `bevy_text`
because it only supports the UI atm.
We can add a `Text2d` version in a followup but getting the same effect
in `Text2d` is trivial even without official support.

---

## Showcase

<img width="122" alt="text_shadow"
src="https://github.com/user-attachments/assets/0333d167-c507-4262-b93b-b6d39e2cf3a4"
/>
<img width="136" alt="g"
src="https://github.com/user-attachments/assets/9b01d5d9-55c9-4af7-9360-a7b04f55944d"
/>
2025-02-05 19:29:37 +00:00
ickshonpe
6be11a8a42
Change GhostNode into a unit type (#17692)
# Objective

The feature gates for the `UiChildren` and `UiRootNodes` system params
make the unconstructable `GhostNode` `PhantomData` trick redundant.


## Solution

Remove the `GhostNode::new` method and change `GhostNode` into a unit
struct.

## Testing

```cargo run --example ghost_nodes```

still works
2025-02-05 18:44:37 +00:00
Rob Parrett
adcc80c43d
Improve TextSpan docs (#17415)
# Objective

Our
[`TextSpan`](https://docs.rs/bevy/latest/bevy/prelude/struct.TextSpan.html)
docs include a code example that does not actually "work." The code
silently does not render anything, and the `Text*Writer` helpers fail.

This seems to be by design, because we can't use `Text` or `Text2d` from
`bevy_ui` or `bevy_sprite` within docs in `bevy_text`. (Correct me if I
am wrong)

I have seen multiple users confused by these docs.

Also fixes #16794

## Solution

Remove the code example from `TextSpan`, and instead encourage users to
seek docs on `Text` or `Text2d`.

Add examples with nested `TextSpan`s in those areas.
2025-02-03 21:36:52 +00:00
ickshonpe
f62775235d
Revert #17631 (#17660)
# Objective

Revert #17631

After some more experimentation, realised it's not the right approach.
2025-02-03 19:01:15 +00:00
Erick Z
416100a253
Fixing ValArithmeticError typo and unused variant (#17597)
# Objective

- `ValArithmeticError` contains a typo, and one of it's variants is not
used

## Solution

- Rename `NonEvaluateable::NonEvaluateable ` variant to
`NonEvaluateable::NonEvaluable`.
- Remove variant `ValArithmeticError:: NonIdenticalVariants`.

## Testing

- `cargo run -p ci`

---

## Migration Guide


- `ValArithmeticError::NonEvaluateable` has been renamed to
`NonEvaluateable::NonEvaluable`
- `ValArithmeticError::NonIdenticalVariants ` has been removed
2025-02-02 15:10:14 +00:00
ickshonpe
89a1c49377
Fix Taffy viewport node leaks (#17596)
# Objective

For most UI node entities there's a 1-to-1 mapping from the entity to
its associated Taffy node. Root UI nodes are an exception though, their
corresponding Taffy node in the Taffy tree is also given a parent that
represents the viewport. These viewport Taffy nodes are not removed when
a root UI node is despawned.

Parenting of an existing root UI node with an associated viewport Taffy
node also results in the leak of the viewport node.

These tests fail if added to the `layout` module's tests on the main
branch:

```rust
    #[test]
    fn no_viewport_node_leak_on_root_despawned() {
        let (mut world, mut ui_schedule) = setup_ui_test_world();

        let ui_root_entity = world.spawn(Node::default()).id();

        // The UI schedule synchronizes Bevy UI's internal `TaffyTree` with the
        // main world's tree of `Node` entities.
        ui_schedule.run(&mut world);

        // Two taffy nodes are added to the internal `TaffyTree` for each root UI entity.
        // An implicit taffy node representing the viewport and a taffy node corresponding to the
        // root UI entity which is parented to the viewport taffy node.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            2
        );

        world.despawn(ui_root_entity);

        // The UI schedule removes both the taffy node corresponding to `ui_root_entity` and its
        // parent viewport node.
        ui_schedule.run(&mut world);

        // Both taffy nodes should now be removed from the internal `TaffyTree`
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            0
        );
    }

    #[test]
    fn no_viewport_node_leak_on_parented_root() {
        let (mut world, mut ui_schedule) = setup_ui_test_world();

        let ui_root_entity_1 = world.spawn(Node::default()).id();
        let ui_root_entity_2 = world.spawn(Node::default()).id();

        ui_schedule.run(&mut world);

        // There are two UI root entities. Each root taffy node is given it's own viewport node parent,
        // so a total of four taffy nodes are added to the `TaffyTree` by the UI schedule.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            4
        );

        // Parent `ui_root_entity_2` onto `ui_root_entity_1` so now only `ui_root_entity_1` is a
        // UI root entity.
        world
            .entity_mut(ui_root_entity_1)
            .add_child(ui_root_entity_2);

        // Now there is only one root node so the second viewport node is removed by
        // the UI schedule.
        ui_schedule.run(&mut world);

        // There is only one viewport node now, so the `TaffyTree` contains 3 nodes in total.
        assert_eq!(
            world.resource_mut::<UiSurface>().taffy.total_node_count(),
            3
        );
    }
```

Fixes #17594

## Solution

Change the `UiSurface::entity_to_taffy` to map to `LayoutNode`s. A
`LayoutNode` has a `viewport_id: Option<taffy::NodeId>` field which is
the id of the corresponding implicit "viewport" node if the node is a
root UI node, otherwise it is `None`. When removing or parenting nodes
this field is checked and the implicit viewport node is removed if
present.

## Testing

There are two new tests in `bevy_ui::layout::tests` included with this
PR:
* `no_viewport_node_leak_on_root_despawned`
* `no_viewport_node_leak_on_parented_root`
2025-02-02 15:03:10 +00:00
ickshonpe
74acb95ed3
anti-alias outside the edges of UI nodes, not across them (#17631)
# Objective

Fixes #17561

## Solution

The anti-aliasing function used by the UI fragment shader is this:
```wgsl
fn antialias(distance: f32) -> f32 {
    return saturate(0.5 - distance);      // saturate clamps between 0 and 1
}
```
The returned value is multiplied with the alpha channel value to get the
anti-aliasing effect.

The `distance` is a signed distance value. A positive `distance` means
we are outside the shape we're drawing and a negative `distance` means
we are on the inside.

So with `distance` at `0` (on the edge of the shape):
```
antialias(0) = saturate(0.5 - 0) = saturate(0.5) = 0.5
```
but we want it to be `1` at this point, so the entire interior of the
shape is given a solid colour, and then decrease as the signed distance
increases.

So in this PR we change it to:
```wgsl
fn antialias(distance: f32) -> f32 {
    return saturate(1. - distance);
}
```
Then:
```
antialias(-0.5) = saturate(1 - (-1)) = saturate(2) = 1
antialias(1) = saturate(1 - 0) = 1
antialias(0.5) = saturate(1 - 0.5) = 0.5
antialias(1) = saturate(1 - 1) = 0
```
as desired.

## Testing

```cargo run --example button```

On main:
<img width="400" alt="bleg" src="https://github.com/user-attachments/assets/314994cb-4529-479d-b179-18e5c25f75bc" />

With this PR:
<img width="400" alt="bbwhite" src="https://github.com/user-attachments/assets/072f481d-8b67-4fae-9a5f-765090d1713f" />

Modified the `button` example to draw a white background to make the bleeding more obvious.
2025-02-02 14:44:31 +00:00
ickshonpe
ba1b0092e5
Extract UI nodes into a Vec (#17618)
# Objective

Extract UI nodes into a `Vec` instead of an `EntityHashMap`.

## Solution

Extract UI nodes into a `Vec` instead of an `EntityHashMap`.
Store an index into the `Vec` in each transparent UI item.
Compare both the index and render entity in prepare so there aren't any
collisions.

## Showcase

Yellow this PR, Red main

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

`extract_uinode_background_colors`
<img width="448" alt="extract_uinode_background_colors"
src="https://github.com/user-attachments/assets/09c0f434-ab4f-4c0f-956a-cf31e9060061"
/>

`extract_uinode_images`
<img width="587" alt="extract_uinode_images"
src="https://github.com/user-attachments/assets/43246d7f-d22c-46d0-9a07-7e13d5379f56"
/>

`prepare_uinodes`
<img width="441" alt="prepare_uinodes_vec"
src="https://github.com/user-attachments/assets/cc9a7eac-60e9-42fa-8093-bce833a1c153"
/>
2025-01-30 23:25:07 +00:00
Jean Mertz
6bda03cc08
chore: impl PartialEq for bevy_ui::Text and bevy_text::TextColor (#17606)
Adding these allows using `DetectChangesMut::set_if_neq` to only update
the values when needed. Currently you need to get the inner values first
(`String` and `Color`), to do any equality checks.

---------

Signed-off-by: Jean Mertz <git@jeanmertz.com>
2025-01-30 04:47:29 +00:00
ickshonpe
d4356062bf
UiSurface::upsert_node refactor (#8831)
# Objective

Simplify the `UiSurface::upsert_node` method by directly matching on
HashMap entry states.
2025-01-28 18:05:59 +00:00
ickshonpe
5bbcf646a7
Improved UI camera mapping (#17244)
# Objective

Two more optimisations for UI extraction:
* We only need to query for the camera's render entity when the target
camera changes. If the target camera is the same as for the previous UI
node we can use the previous render entity.
* The cheap checks for visibility and zero size should be performed
first before the camera queries.

## Solution
Add a new system param `UiCameraMap` that resolves the correct render
camera entity and only queries when necessary.

<img width="506" alt="tracee"
src="https://github.com/user-attachments/assets/f57d1e0d-f3a7-49ee-8287-4f01ffc8ba24"
/>

I don't like the `UiCameraMap` + `UiCameraMapper` implementation very
much, maybe someone else can suggest a better construction.

This is partly motivated by #16942 which adds further indirection and
these changes would ameliorate that performance regression.
2025-01-28 18:05:00 +00:00
ickshonpe
a80263a5bf
no-camera many_buttons argument, only emit UI camera warnings once (#17557)
# Objective

* Add a `no-camera` argument to the `many_buttons` stress test example.
* Only emit the UI "no camera found" warnings once.
2025-01-28 18:04:52 +00:00
Luc
51bb4f08a9
expose OverflowAxis::Hidden as Overflow functions (#17528)
# Objective
expose `OverflowAxis::Hidden` as functions of `Overflow`, just as it is
done for `OverflowAxis::Hidden` and `OverflowAxis::Scroll`.
2025-01-28 05:34:50 +00:00
ickshonpe
c0ccc87738
UI material border radius (#15171)
# Objective

I wrote a box shadow UI material naively thinking I could use the border
widths attribute to hold the border radius but it
doesn't work as the border widths are automatically set in the
extraction function. Need to send border radius to the shader seperately
for it to be viable.

## Solution

Add a `border_radius` vertex attribute to the ui material.

This PR also removes the normalization of border widths for custom UI
materials. The regular UI shader doesn't do this so it's a bit confusing
and means you can't use the logic from `ui.wgsl` in your custom UI
materials.

## Testing / Showcase

Made a change to the `ui_material` example to display border radius:

```cargo run --example ui_material```

<img width="569" alt="corners" src="https://github.com/user-attachments/assets/36412736-a9ee-4042-aadd-68b9cafb17cb" />
2025-01-28 04:54:48 +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
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
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
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
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
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
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
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
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
ickshonpe
adc33b5108
Rename TargetCamera to UiTargetCamera (#17403)
# Objective

It's not immediately obvious that `TargetCamera` only works with UI node
entities. It's natural to assume from looking at something like the
`multiple_windows` example that it will work with everything.

## Solution

Rename `TargetCamera` to `UiTargetCamera`.

## Migration Guide

`TargetCamera` has been renamed to `UiTargetCamera`.
2025-01-19 19:56:57 +00:00
Carter Anderson
21f1e3045c
Relationships (non-fragmenting, one-to-many) (#17398)
This adds support for one-to-many non-fragmenting relationships (with
planned paths for fragmenting and non-fragmenting many-to-many
relationships). "Non-fragmenting" means that entities with the same
relationship type, but different relationship targets, are not forced
into separate tables (which would cause "table fragmentation").

Functionally, this fills a similar niche as the current Parent/Children
system. The biggest differences are:

1. Relationships have simpler internals and significantly improved
performance and UX. Commands and specialized APIs are no longer
necessary to keep everything in sync. Just spawn entities with the
relationship components you want and everything "just works".
2. Relationships are generalized. Bevy can provide additional built in
relationships, and users can define their own.

**REQUEST TO REVIEWERS**: _please don't leave top level comments and
instead comment on specific lines of code. That way we can take
advantage of threaded discussions. Also dont leave comments simply
pointing out CI failures as I can read those just fine._

## Built on top of what we have

Relationships are implemented on top of the Bevy ECS features we already
have: components, immutability, and hooks. This makes them immediately
compatible with all of our existing (and future) APIs for querying,
spawning, removing, scenes, reflection, etc. The fewer specialized APIs
we need to build, maintain, and teach, the better.

## Why focus on one-to-many non-fragmenting first?

1. This allows us to improve Parent/Children relationships immediately,
in a way that is reasonably uncontroversial. Switching our hierarchy to
fragmenting relationships would have significant performance
implications. ~~Flecs is heavily considering a switch to non-fragmenting
relations after careful considerations of the performance tradeoffs.~~
_(Correction from @SanderMertens: Flecs is implementing non-fragmenting
storage specialized for asset hierarchies, where asset hierarchies are
many instances of small trees that have a well defined structure)_
2. Adding generalized one-to-many relationships is currently a priority
for the [Next Generation Scene / UI
effort](https://github.com/bevyengine/bevy/discussions/14437).
Specifically, we're interested in building reactions and observers on
top.

## The changes

This PR does the following:

1. Adds a generic one-to-many Relationship system
3. Ports the existing Parent/Children system to Relationships, which now
lives in `bevy_ecs::hierarchy`. The old `bevy_hierarchy` crate has been
removed.
4. Adds on_despawn component hooks
5. Relationships can opt-in to "despawn descendants" behavior, meaning
that the entire relationship hierarchy is despawned when
`entity.despawn()` is called. The built in Parent/Children hierarchies
enable this behavior, and `entity.despawn_recursive()` has been removed.
6. `world.spawn` now applies commands after spawning. This ensures that
relationship bookkeeping happens immediately and removes the need to
manually flush. This is in line with the equivalent behaviors recently
added to the other APIs (ex: insert).
7. Removes the ValidParentCheckPlugin (system-driven / poll based) in
favor of a `validate_parent_has_component` hook.

## Using Relationships

The `Relationship` trait looks like this:

```rust
pub trait Relationship: Component + Sized {
    type RelationshipSources: RelationshipSources<Relationship = Self>;
    fn get(&self) -> Entity;
    fn from(entity: Entity) -> Self;
}
```

A relationship is a component that:

1. Is a simple wrapper over a "target" Entity.
2. Has a corresponding `RelationshipSources` component, which is a
simple wrapper over a collection of entities. Every "target entity"
targeted by a "source entity" with a `Relationship` has a
`RelationshipSources` component, which contains every "source entity"
that targets it.

For example, the `Parent` component (as it currently exists in Bevy) is
the `Relationship` component and the entity containing the Parent is the
"source entity". The entity _inside_ the `Parent(Entity)` component is
the "target entity". And that target entity has a `Children` component
(which implements `RelationshipSources`).

In practice, the Parent/Children relationship looks like this:

```rust
#[derive(Relationship)]
#[relationship(relationship_sources = Children)]
pub struct Parent(pub Entity);

#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent)]
pub struct Children(Vec<Entity>);
```

The Relationship and RelationshipSources derives automatically implement
Component with the relevant configuration (namely, the hooks necessary
to keep everything in sync).

The most direct way to add relationships is to spawn entities with
relationship components:

```rust
let a = world.spawn_empty().id();
let b = world.spawn(Parent(a)).id();

assert_eq!(world.entity(a).get::<Children>().unwrap(), &[b]);
```

There are also convenience APIs for spawning more than one entity with
the same relationship:

```rust
world.spawn_empty().with_related::<Children>(|s| {
    s.spawn_empty();
    s.spawn_empty();
})
```

The existing `with_children` API is now a simpler wrapper over
`with_related`. This makes this change largely non-breaking for existing
spawn patterns.

```rust
world.spawn_empty().with_children(|s| {
    s.spawn_empty();
    s.spawn_empty();
})
```

There are also other relationship APIs, such as `add_related` and
`despawn_related`.

## Automatic recursive despawn via the new on_despawn hook

`RelationshipSources` can opt-in to "despawn descendants" behavior,
which will despawn all related entities in the relationship hierarchy:

```rust
#[derive(RelationshipSources)]
#[relationship_sources(relationship = Parent, despawn_descendants)]
pub struct Children(Vec<Entity>);
```

This means that `entity.despawn_recursive()` is no longer required.
Instead, just use `entity.despawn()` and the relevant related entities
will also be despawned.

To despawn an entity _without_ despawning its parent/child descendants,
you should remove the `Children` component first, which will also remove
the related `Parent` components:

```rust
entity
    .remove::<Children>()
    .despawn()
```

This builds on the on_despawn hook introduced in this PR, which is fired
when an entity is despawned (before other hooks).

## Relationships are the source of truth

`Relationship` is the _single_ source of truth component.
`RelationshipSources` is merely a reflection of what all the
`Relationship` components say. By embracing this, we are able to
significantly improve the performance of the system as a whole. We can
rely on component lifecycles to protect us against duplicates, rather
than needing to scan at runtime to ensure entities don't already exist
(which results in quadratic runtime). A single source of truth gives us
constant-time inserts. This does mean that we cannot directly spawn
populated `Children` components (or directly add or remove entities from
those components). I personally think this is a worthwhile tradeoff,
both because it makes the performance much better _and_ because it means
theres exactly one way to do things (which is a philosophy we try to
employ for Bevy APIs).

As an aside: treating both sides of the relationship as "equivalent
source of truth relations" does enable building simple and flexible
many-to-many relationships. But this introduces an _inherent_ need to
scan (or hash) to protect against duplicates.
[`evergreen_relations`](https://github.com/EvergreenNest/evergreen_relations)
has a very nice implementation of the "symmetrical many-to-many"
approach. Unfortunately I think the performance issues inherent to that
approach make it a poor choice for Bevy's default relationship system.

## Followup Work

* Discuss renaming `Parent` to `ChildOf`. I refrained from doing that in
this PR to keep the diff reasonable, but I'm personally biased toward
this change (and using that naming pattern generally for relationships).
* [Improved spawning
ergonomics](https://github.com/bevyengine/bevy/discussions/16920)
* Consider adding relationship observers/triggers for "relationship
targets" whenever a source is added or removed. This would replace the
current "hierarchy events" system, which is unused upstream but may have
existing users downstream. I think triggers are the better fit for this
than a buffered event queue, and would prefer not to add that back.
* Fragmenting relations: My current idea hinges on the introduction of
"value components" (aka: components whose type _and_ value determines
their ComponentId, via something like Hashing / PartialEq). By labeling
a Relationship component such as `ChildOf(Entity)` as a "value
component", `ChildOf(e1)` and `ChildOf(e2)` would be considered
"different components". This makes the transition between fragmenting
and non-fragmenting a single flag, and everything else continues to work
as expected.
* Many-to-many support
* Non-fragmenting: We can expand Relationship to be a list of entities
instead of a single entity. I have largely already written the code for
this.
* Fragmenting: With the "value component" impl mentioned above, we get
many-to-many support "for free", as it would allow inserting multiple
copies of a Relationship component with different target entities.

Fixes #3742 (If this PR is merged, I think we should open more targeted
followup issues for the work above, with a fresh tracking issue free of
the large amount of less-directed historical context)
Fixes #17301
Fixes #12235 
Fixes #15299
Fixes #15308 

## Migration Guide

* Replace `ChildBuilder` with `ChildSpawnerCommands`.
* Replace calls to `.set_parent(parent_id)` with
`.insert(Parent(parent_id))`.
* Replace calls to `.replace_children()` with `.remove::<Children>()`
followed by `.add_children()`. Note that you'll need to manually despawn
any children that are not carried over.
* Replace calls to `.despawn_recursive()` with `.despawn()`.
* Replace calls to `.despawn_descendants()` with
`.despawn_related::<Children>()`.
* If you have any calls to `.despawn()` which depend on the children
being preserved, you'll need to remove the `Children` component first.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2025-01-18 22:20:30 +00:00
ickshonpe
daf665cc74
Clip outlines using the local clipping rect. (#17385)
# Objective

UI node Outlines are clipped using their parent's clipping rect instead
of their own.

## Solution

Clip outlines using the UI node's own clipping rect.
2025-01-15 18:19:35 +00:00
MichiRecRoom
26bb0b40d2
Move #![warn(clippy::allow_attributes, clippy::allow_attributes_without_reason)] to the workspace Cargo.toml (#17374)
# Objective
Fixes https://github.com/bevyengine/bevy/issues/17111

## Solution
Move `#![warn(clippy::allow_attributes,
clippy::allow_attributes_without_reason)]` to the workspace `Cargo.toml`

## Testing
Lots of CI testing, and local testing too.

---------

Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
2025-01-15 01:14:58 +00:00
Patrick Walton
35101f3ed5
Use multi_draw_indirect_count where available, in preparation for two-phase occlusion culling. (#17211)
This commit allows Bevy to use `multi_draw_indirect_count` for drawing
meshes. The `multi_draw_indirect_count` feature works just like
`multi_draw_indirect`, but it takes the number of indirect parameters
from a GPU buffer rather than specifying it on the CPU.

Currently, the CPU constructs the list of indirect draw parameters with
the instance count for each batch set to zero, uploads the resulting
buffer to the GPU, and dispatches a compute shader that bumps the
instance count for each mesh that survives culling. Unfortunately, this
is inefficient when we support `multi_draw_indirect_count`. Draw
commands corresponding to meshes for which all instances were culled
will remain present in the list when calling
`multi_draw_indirect_count`, causing overhead. Proper use of
`multi_draw_indirect_count` requires eliminating these empty draw
commands.

To address this inefficiency, this PR makes Bevy fully construct the
indirect draw commands on the GPU instead of on the CPU. Instead of
writing instance counts to the draw command buffer, the mesh
preprocessing shader now writes them to a separate *indirect metadata
buffer*. A second compute dispatch known as the *build indirect
parameters* shader runs after mesh preprocessing and converts the
indirect draw metadata into actual indirect draw commands for the GPU.
The build indirect parameters shader operates on a batch at a time,
rather than an instance at a time, and as such each thread writes only 0
or 1 indirect draw parameters, simplifying the current logic in
`mesh_preprocessing`, which currently has to have special cases for the
first mesh in each batch. The build indirect parameters shader emits
draw commands in a tightly packed manner, enabling maximally efficient
use of `multi_draw_indirect_count`.

Along the way, this patch switches mesh preprocessing to dispatch one
compute invocation per render phase per view, instead of dispatching one
compute invocation per view. This is preparation for two-phase occlusion
culling, in which we will have two mesh preprocessing stages. In that
scenario, the first mesh preprocessing stage must only process opaque
and alpha tested objects, so the work items must be separated into those
that are opaque or alpha tested and those that aren't. Thus this PR
splits out the work items into a separate buffer for each phase. As this
patch rewrites so much of the mesh preprocessing infrastructure, it was
simpler to just fold the change into this patch instead of deferring it
to the forthcoming occlusion culling PR.

Finally, this patch changes mesh preprocessing so that it runs
separately for indexed and non-indexed meshes. This is because draw
commands for indexed and non-indexed meshes have different sizes and
layouts. *The existing code is actually broken for non-indexed meshes*,
as it attempts to overlay the indirect parameters for non-indexed meshes
on top of those for indexed meshes. Consequently, right now the
parameters will be read incorrectly when multiple non-indexed meshes are
multi-drawn together. *This is a bug fix* and, as with the change to
dispatch phases separately noted above, was easiest to include in this
patch as opposed to separately.

## Migration Guide

* Systems that add custom phase items now need to populate the indirect
drawing-related buffers. See the `specialized_mesh_pipeline` example for
an example of how this is done.
2025-01-14 21:19:20 +00:00
Patrick Walton
141b7673ab
Key render phases off the main world view entity, not the render world view entity. (#16942)
We won't be able to retain render phases from frame to frame if the keys
are unstable. It's not as simple as simply keying off the main world
entity, however, because some main world entities extract to multiple
render world entities. For example, directional lights extract to
multiple shadow cascades, and point lights extract to one view per
cubemap face. Therefore, we key off a new type, `RetainedViewEntity`,
which contains the main entity plus a *subview ID*.

This is part of the preparation for retained bins.

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2025-01-12 20:24:17 +00:00
Antony
02bb151889
Rename PickingBehavior to Pickable (#17266)
# Objective

PR #17225 allowed for sprite picking to be opt-in. After some
discussion, it was agreed that `PickingBehavior` should be used to
opt-in to sprite picking behavior for entities. This leads to
`PickingBehavior` having two purposes: mark an entity for use in a
backend, and describe how it should be picked. Discussion led to the
name `Pickable`making more sense (also: this is what the component was
named before upstreaming).

A follow-up pass will be made after this PR to unify backends.

## Solution

Replace all instances of `PickingBehavior` and `picking_behavior` with
`Pickable` and `pickable`, respectively.

## Testing

CI

## Migration Guide

Change all instances of `PickingBehavior` to `Pickable`.
2025-01-12 05:36:52 +00:00
ickshonpe
8ac1f8ccdc
Rename UI camera_entity fields (#17243)
# Objective

The `camera_entity` field on the extracted uinode structs holds the
render world entity that has the extracted camera components
corresponding to the target camera world entity. It should be renamed so
that it's clear it isn't the target camera world entity itself.

## Solution

Rename the `camera_entity` field on each of the extracted UI item
structs to `extracted_camera_entity`.
2025-01-12 05:32:08 +00:00
MichiRecRoom
447108b2a4
Downgrade clippy::allow_attributes and clippy::allow_attributes_without_reason to warn (#17320)
# Objective
I realized that setting these to `deny` may have been a little
aggressive - especially since we upgrade warnings to denies in CI.

## Solution
Downgrades these lints to `warn`, so that compiles can work locally. CI
will still treat these as denies.
2025-01-12 05:28:26 +00:00
MichiRecRoom
3742e621ef
Allow clippy::too_many_arguments to lint without warnings (#17249)
# Objective
Many instances of `clippy::too_many_arguments` linting happen to be on
systems - functions which we don't call manually, and thus there's not
much reason to worry about the argument count.

## Solution
Allow `clippy::too_many_arguments` globally, and remove all lint
attributes related to it.
2025-01-09 07:26:15 +00:00
ickshonpe
532bb15489
extract_shadows responsive coords fix (#17236)
# Objective

`extract_shadows` uses the render world entity corresponding to the
extracted camera when it queries the main world for the camera to get
the viewport size for the responsive viewport coords resolution and
fails. This means that viewport coords get resolved based on a viewport
size of zero.

## Solution

Use the main world camera entity.
2025-01-09 06:29:09 +00:00
MichiRecRoom
71cd5f813e
Fix up the reason given for a couple of too_many_arguments lints (#17251)
# Objective
In my crusade to give every lint attribute a reason, it appears I got
too complacent and copy-pasted this expect onto non-system functions.

## Solution
Fix up the reason on those non-system functions

## Testing
N/A
2025-01-09 02:39:10 +00:00
MichiRecRoom
8b4c25ad5f
bevy_ui: Apply #![deny(clippy::allow_attributes, clippy::allow_attributes_without_reason)] (#17229)
# Objective
- https://github.com/bevyengine/bevy/issues/17111

## Solution
Set the `clippy::allow_attributes` and
`clippy::allow_attributes_without_reason` lints to `deny`, and bring
`bevy_ui` in line with the new restrictions.

## Testing
`cargo clippy --tests` and `cargo test --package bevy_ui` were run, and
no errors were encountered.
2025-01-08 19:30:19 +00:00
ickshonpe
e896c364dc
Rename DefaultCameraView (#17235)
# Objective

The name `DefaultCameraView` is confusing and misleading:
* It isn't the default UI camera, which is either the camera with the
`IsDefaultUiCamera` marker component or, if no such camera is found, the
camera with the highest order which has the primary window as its render
target.
* It doesn't make sense to call it a "default", every active 2d and 3d
camera is given its own `DefaultCameraView`.
* The name doesn't make it clear that it's UI specific component.

## Solution

Rename `DefaultCameraView` to `UiCameraView`, add a doc comment for it
and rename a few other fields and variables.

## Migration Guide

`DefaultCameraView` has been renamed to `UiCameraView`
2025-01-08 18:44:11 +00:00
mgi388
e24ae6cf40
Move TextureAtlas and friends into bevy_image (#17219)
# Objective

- Allow other crates to use `TextureAtlas` and friends without needing
to depend on `bevy_sprite`.
- Specifically, this allows adding `TextureAtlas` support to custom
cursors in https://github.com/bevyengine/bevy/pull/17121 by allowing
`bevy_winit` to depend on `bevy_image` instead of `bevy_sprite` which is
a [non-starter].

[non-starter]:
https://github.com/bevyengine/bevy/pull/17121#discussion_r1904955083

## Solution

- Move `TextureAtlas`, `TextureAtlasBuilder`, `TextureAtlasSources`,
`TextureAtlasLayout` and `DynamicTextureAtlasBuilder` into `bevy_image`.
- Add a new plugin to `bevy_image` named `TextureAtlasPlugin` which
allows us to register `TextureAtlas` and `TextureAtlasLayout` which was
previously done in `SpritePlugin`. Since `SpritePlugin` did the
registration previously, we just need to make it add
`TextureAtlasPlugin`.

## Testing

- CI builds it.
- I also ran multiple examples which hopefully covered any issues:

```
$ cargo run --example sprite
$ cargo run --example text
$ cargo run --example ui_texture_atlas
$ cargo run --example sprite_animation
$ cargo run --example sprite_sheet
$ cargo run --example sprite_picking
```

---

## Migration Guide

The following types have been moved from `bevy_sprite` to `bevy_image`:
`TextureAtlas`, `TextureAtlasBuilder`, `TextureAtlasSources`,
`TextureAtlasLayout` and `DynamicTextureAtlasBuilder`.

If you are using the `bevy` crate, and were importing these types
directly (e.g. before `use bevy::sprite::TextureAtlas`), be sure to
update your import paths (e.g. after `use bevy::image::TextureAtlas`)

If you are using the `bevy` prelude to import these types (e.g. `use
bevy::prelude::*`), you don't need to change anything.

If you are using the `bevy_sprite` subcrate, be sure to add `bevy_image`
as a dependency if you do not already have it, and be sure to update
your import paths.
2025-01-07 18:43:11 +00:00
ickshonpe
17e3b850bd
Simplified UI tree navigation without ghost_nodes (#17143)
# Objective

There is a large performance regression in the UI systems in 0.15
because the `UiChildren` and `UiRootRootNodes` system params (even with
`ghost_nodes` disabled) are really inefficient compared to regular
queries and can trigger a heap allocation with large numbers of
children.

## Solution

Replace the `UiChildren` and `UiRootRootNodes` system params with
simplified versions when the `ghost_nodes` feature is disabled.

## Testing

yellow this PR, red main

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

`ui_stack_system`
<img width="494" alt="stack"
src="https://github.com/user-attachments/assets/4a09485f-0ded-4e54-bd47-ffbce869051a"
/>

`ui_layout_system`
<img width="467" alt="unghosted"
src="https://github.com/user-attachments/assets/9d906b20-66b6-4257-9eef-578de1827628"
/>

`update_clipping_system`
<img width="454" alt="clipping"
src="https://github.com/user-attachments/assets/320b50e8-1a1d-423a-95a0-42799ae72fc5"
/>
2025-01-06 19:22:00 +00:00
ickshonpe
d220eccbb1
More DefaultUiCamera fixes (#17120)
# Objective

Found more excessive `DefaultUiCamera` queries outside of extraction.
The default UI camera lookup only needs to be done once. Do it first,
not per node.

---------

Co-authored-by: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com>
2025-01-06 19:11:04 +00:00