Commit graph

5563 commits

Author SHA1 Message Date
François
a00c71ee5b
Cleanup deterministic example (#11416)
# Objective

- Example `deterministic` crashes on CI on Windows because it uses too
much memory

## Solution

- Reduce the number of planes displayed while still having the issue
- While there, add a small margin to the text so that it's prettier
2024-01-19 06:08:19 +00:00
Lee-Orr
e9b8c71da0
move once from bevy_log to bevy_utils, to allow for it's use in bevy_ecs (#11419)
# Objective

When working within `bevy_ecs`, we can't use the `log_once` macros due
to their placement in `bevy_log` - which depends on `bevy_ecs`. All this
create does is migrate those macros to the `bevy_utils` crate, while
still re-exporting them in `bevy_log`.

created to resolve this:
https://github.com/bevyengine/bevy/pull/11417#discussion_r1458100211

---------

Co-authored-by: François <mockersf@gmail.com>
2024-01-19 06:07:41 +00:00
pablo-lua
6fbd585d78
Fix gizmos app new panic (#11420)
# Objective

After the Gizmos changes, `App::init_gizmos_group` turned into a
important function that for sure mustn't panic. The problem is: the
actual implementation causes a panic if somehow the code is runned
before `GizmoPlugin` was added to the App
- The error occurs here for example:
```rust
fn main() {
    App::new()
        .init_gizmo_group::<MyGizmoConfig>()
        .add_plugins(DefaultPlugins)
        .run();
}

#[derive(Default, Reflect, GizmoConfigGroup)]
struct MyGizmoConfig;
```

![image](https://github.com/bevyengine/bevy/assets/126117294/35e75608-0946-4320-8035-00a82562e37e)


## Solution

- Instead of panicking when getting `GizmoConfigStore`, insert the store
in `App::init_gizmos_group` if needed

---

## Changelog

### Changed
- Changed App::init_gizmos_group to insert the resource if it don't
exist

### Removed
- Removed explicit init of `GizmoConfigStore`

---------

Co-authored-by: François <mockersf@gmail.com>
2024-01-19 06:03:27 +00:00
François
cd2cdb475a
Miri is failing on latest nightly: pin nightly to last known working version (#11421)
# Objective

- https://github.com/rust-lang/rust/pull/118553 seems to have broken
miri test

## Solution

- Pin nightly to before it was merged
2024-01-19 05:29:10 +00:00
IceSentry
7125dcb268
Customizable camera main texture usage (#11412)
# Objective

- Some users want to change the default texture usage of the main camera
but they are currently hardcoded

## Solution

- Add a component that is used to configure the main texture usage field

---

## Changelog

Added `CameraMainTextureUsage`
Added `CameraMainTextureUsage` to `Camera3dBundle` and `Camera2dBundle`

## Migration Guide

Add `main_texture_usages: Default::default()` to your camera bundle.

# Notes

Inspired by: #6815
2024-01-18 20:33:42 +00:00
Doonv
03ee959809
Fix panic on Text UI without Cameras (#11405)
# Objective

Fix https://github.com/bevyengine/bevy/issues/11396.

## Solution

Don't panic on taffy node not existing.

Plus minor warning text improvement.
2024-01-18 20:33:22 +00:00
BD103
056b006d4e
Use static_assertions to check for trait impls (#11407)
# Objective

- Tests are manually checking whether derived types implement certain
traits. (Specifically in `bevy_reflect.)
- #11182 introduces
[`static_assertions`](https://docs.rs/static_assertions/) to
automatically check this.
- Simplifies `Reflect` test in #11195.
- Closes #11196.

## Solution

- Add `static_assertions` and replace current tests.

---

I wasn't sure whether to remove the existing test or not. What do you
think?
2024-01-18 17:21:18 +00:00
Eris
d151883f3e
Get Change Tick methods for Resources (#11404)
# Objective

- Add methods to get Change Ticks for a given resource by type or
ComponentId
- Fixes #11390
The `is_resource_id_changed` requested in the Issue already exists, this
adds their request for `get_resource_change_ticks`

## Solution

- Added two methods to get change ticks by Type or ComponentId
2024-01-18 15:58:13 +00:00
Joona Aalto
c62ad4b2c4
Implement bounding volumes for primitive shapes (#11336)
# Objective

Closes #10570.

#10946 added bounding volume types and traits, but didn't use them for
anything yet. This PR implements `Bounded2d` and `Bounded3d` for Bevy's
primitive shapes.

## Solution

Implement `Bounded2d` and `Bounded3d` for primitive shapes. This allows
computing AABBs and bounding circles/spheres for them.

For most shapes, there are several ways of implementing bounding
volumes. I took inspiration from [Parry's bounding
volumes](https://github.com/dimforge/parry/tree/master/src/bounding_volume),
[Inigo Quilez](http://iquilezles.org/articles/diskbbox/), and figured
out the rest myself using geometry. I tried to comment all slightly
non-trivial or unclear math to make it understandable.

Parry uses support mapping (finding the farthest point in some direction
for convex shapes) for some AABBs like cones, cylinders, and line
segments. This involves several quat operations and normalizations, so I
opted for the simpler and more efficient geometric approaches shown in
[Quilez's article](http://iquilezles.org/articles/diskbbox/).

Below you can see some of the bounding volumes working in 2D and 3D.
Note that I can't conveniently add these examples yet because they use
primitive shape meshing, which is still WIP.


https://github.com/bevyengine/bevy/assets/57632562/4465cbc6-285b-4c71-b62d-a2b3ee16f8b4


https://github.com/bevyengine/bevy/assets/57632562/94b4ac84-a092-46d7-b438-ce2e971496a4

---

## Changelog

- Implemented `Bounded2d`/`Bounded3d` for primitive shapes
- Added `from_point_cloud` method for bounding volumes (used by many
bounding implementations)
- Added `point_cloud_2d/3d_center` and `rotate_vec2` utility functions
- Added `RegularPolygon::vertices` method (used in regular polygon AABB
construction)
- Added `Triangle::circumcenter` method (used in triangle bounding
circle construction)
- Added bounding circle/sphere creation from AABBs and vice versa

## Extra

Do we want to implement `Bounded2d` for some "3D-ish" shapes too? For
example, capsules are sort of dimension-agnostic and useful for 2D, so I
think that would be good to implement. But a cylinder in 2D is just a
rectangle, and a cone is a triangle, so they wouldn't make as much sense
to me. A conical frustum would be an isosceles trapezoid, which could be
useful, but I'm not sure if computing the 2D AABB of a 3D frustum makes
semantic sense.
2024-01-18 15:55:36 +00:00
jeliag
f6b40a6e43
Multiple Configurations for Gizmos (#10342)
# Objective

This PR aims to implement multiple configs for gizmos as discussed in
#9187.

## Solution

Configs for the new `GizmoConfigGroup`s are stored in a
`GizmoConfigStore` resource and can be accesses using a type based key
or iterated over. This type based key doubles as a standardized location
where plugin authors can put their own configuration not covered by the
standard `GizmoConfig` struct. For example the `AabbGizmoGroup` has a
default color and toggle to show all AABBs. New configs can be
registered using `app.init_gizmo_group::<T>()` during startup.

When requesting the `Gizmos<T>` system parameter the generic type
determines which config is used. The config structs are available
through the `Gizmos` system parameter allowing for easy access while
drawing your gizmos.

Internally, resources and systems used for rendering (up to an including
the extract system) are generic over the type based key and inserted on
registering a new config.

## Alternatives

The configs could be stored as components on entities with markers which
would make better use of the ECS. I also implemented this approach
([here](https://github.com/jeliag/bevy/tree/gizmo-multiconf-comp)) and
believe that the ergonomic benefits of a central config store outweigh
the decreased use of the ECS.

## Unsafe Code

Implementing system parameter by hand is unsafe but seems to be required
to access the config store once and not on every gizmo draw function
call. This is critical for performance. ~Is there a better way to do
this?~

## Future Work

New gizmos (such as #10038, and ideas from #9400) will require custom
configuration structs. Should there be a new custom config for every
gizmo type, or should we group them together in a common configuration?
(for example `EditorGizmoConfig`, or something more fine-grained)

## Changelog

- Added `GizmoConfigStore` resource and `GizmoConfigGroup` trait
- Added `init_gizmo_group` to `App`
- Added early returns to gizmo drawing increasing performance when
gizmos are disabled
- Changed `GizmoConfig` and aabb gizmos to use new `GizmoConfigStore`
- Changed `Gizmos` system parameter to use type based key to retrieve
config
- Changed resources and systems used for gizmo rendering to be generic
over type based key
- Changed examples (3d_gizmos, 2d_gizmos) to showcase new API

## Migration Guide

- `GizmoConfig` is no longer a resource and has to be accessed through
`GizmoConfigStore` resource. The default config group is
`DefaultGizmoGroup`, but consider using your own custom config group if
applicable.

---------

Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2024-01-18 15:52:50 +00:00
Brian Reavis
c9e1fcdb35
Added AssetLoadFailedEvent, UntypedAssetLoadFailedEvent (#11369)
# Objective

This adds events for assets that fail to load along with minor utility
methods to make them useful. This paves the way for users writing their
own error handling and retry systems, plus Bevy including robust retry
handling: #11349.

* Addresses #11288
* Needed for #11349

# Solution

```rust
/// An event emitted when a specific [`Asset`] fails to load.
#[derive(Event, Clone, Debug)]
pub struct AssetLoadFailedEvent<A: Asset> {
    pub id: AssetId<A>,
    /// The original handle returned when the asset load was requested.
    pub handle: Option<Handle<A>>,
    /// The asset path that was attempted.
    pub path: AssetPath<'static>,
    /// Why the asset failed to load.
    pub error: AssetLoadError,
}
```

I started implementing `AssetEvent::Failed` like suggested in #11288,
but decided it was better as its own type because:

* I think it makes sense for `AssetEvent` to only refer to assets that
actually exist.
* In order to return `AssetLoadError` in the event (which is useful
information for error handlers that might attempt a retry) we would have
to remove `Copy` from `AssetEvent`.
* There are numerous places in the render app that match against
`AssetEvent`, and I don't think it's worth introducing extra noise about
assets that don't exist.

I also introduced `UntypedAssetLoadErrorEvent`, which is very useful in
places that need to support type flexibility, like an Asset-agnostic
retry plugin.

# Changelog

* **Added:** `AssetLoadFailedEvent<A>`
* **Added**: `UntypedAssetLoadFailedEvent`
* **Added:** `AssetReaderError::Http` for status code information on
HTTP errors. Before this, status codes were only available by parsing
the error message of generic `Io` errors.
* **Added:** `asset_server.get_path_id(path)`. This method simply gets
the asset id for the path. Without this, one was left using
`get_path_handle(path)`, which has the overhead of returning a strong
handle.
* **Fixed**: Made `AssetServer` loads return the same handle for assets
that already exist in a failed state. Now, when you attempt a `load`
that's in a `LoadState::Failed` state, it'll re-use the original asset
id. The advantage of this is that any dependent assets created using the
original handle will "unbreak" if a retry succeeds.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-17 21:12:00 +00:00
GitGhillie
9abf565138
Restore brightness in the remaining three examples after exposure PR (#11389)
# Objective

Fixes #11376
During the development of the exposure settings PR (#11347) all examples
with lighting had to be adjusted, but three were missed or simply didn't
exist yet at the time. This PR restores the brightness in those examples
again:

render_ui_to_texture
asset_loading
hot_asset_reloading

All of them are a bit brighter now compared to before the exposure PR,
but it looks better IMO.
2024-01-17 17:10:21 +00:00
Architector #4
8db4723373
[doc] Fix typo and formatting in CONTRIBUTING.md (#11381)
# Objective

Issue: There is a typo in `CONTRIBUTING.md` ("then" used in place of
"them"). There is also an inconsistency of usage of periods at ends of
items in lists, and one section is written with non-breaking spaces
without good reason.

## Solution

Fix the aforementioned typo and consistency issues.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Rob Parrett <robparrett@gmail.com>
2024-01-17 17:07:53 +00:00
robtfm
30940e5cb4
fix occasional crash moving ui root nodes (#11371)
# Objective

fix an occasional crash when moving ui root nodes between cameras.

occasionally, updating the TargetCamera of a ui element and then
removing the element causes a crash.

i believe that is because when we assign a child in taffy, the old
parent doesn't remove that child from it's children, so we have:

```
user: create root node N1, camera A
-> layout::set_camera_children(A) : 
	- create implicit node A1
	- assign 1 as child -> taffy.children[A1] = [N1], taffy.parents[1] = A1

user: move root node N1 to camera B
-> layout::set_camera_children(B) :
	- create implicit node B1
	- assign 1 as child -> taffy.children[A1] = [N1], taffy.children[B1] = [N1], taffy.parents[1] = B1
-> layout::set_camera_children(A) :
	- remove implicit node A1 (which still has N1 as a child) -> 
		-> taffy sets parent[N1] = None ***
		-> taffy.children[B1] = [N1], taffy.parents[1] = None

user: remove N1
-> layout::remove_entities(N1)
	- since parent[N1] is None, it's not removed from B1 -> taffy.children[B1] = [N1], taffy.parents[1] is removed
-> layout::set_camera_children(B)
	- remove implicit node B1
	- taffy crash accessing taffy.parents[N1]
```

## Solution

we can work around this by making sure to remove the child from the old
parent if one exists (this pr).

i think a better fix may be for taffy to check in `Taffy::remove` and
only set the child's parent to None if it is currently equal to the node
being removed but i'm not sure if there's an explicit assumption we're
violating here (@nicoburns).
2024-01-17 16:53:27 +00:00
wackbyte
43f83d5e7c
Remove duplicate #[automatically_derived] in ECS macro (#11388)
# Objective

It's already provided by `item_attrs`, so it can be removed.

# Solution

Remove the extra `#[automatically_derived]`.
2024-01-17 16:52:45 +00:00
Mateusz Wachowiak
9a8349ac7b
Run markdownlint (#11386)
# Objective

- Fix formatting in markdown file.

## Solution

- Ran `markdownlint -f -c .github/linters/.markdown-lint.yml .` from
[CONTRIBUTING.md](https://github.com/bevyengine/bevy/blob/main/CONTRIBUTING.md?plain=1#L341)

I came across this when working on `bevy_dev_tools`
2024-01-17 14:27:28 +00:00
Rob Parrett
3a666cab23
Fix link to plugin guidelines (#11379)
# Objective

The document was moved in #11242, so this link is now broken.

## Solution

Swap in a working link.
2024-01-17 07:30:03 +00:00
Giacomo Stevanato
39cca41f3f
Make DynamicUniformBuffer::push accept an &T instead of T (#11373)
# Objective

- `DynamicUniformBuffer::push` takes an owned `T` but only uses a shared
reference to it
- This in turn requires users of `DynamicUniformBuffer::push` to
potentially unecessarily clone data

## Solution

- Have `DynamicUniformBuffer::push` take a shared reference to `T`

---

## Changelog

- `DynamicUniformBuffer::push` now takes a `&T` instead of `T`

## Migration Guide

- Users of `DynamicUniformBuffer::push` now need to pass references to
`DynamicUniformBuffer::push` (e.g. existing `uniforms.push(value)` will
now become `uniforms.push(&value)`)
2024-01-16 20:51:56 +00:00
James O'Brien
ea42d14344
Dynamic queries and builder API (#9774)
# Objective
Expand the existing `Query` API to support more dynamic use cases i.e.
scripting.

## Prior Art
 - #6390 
 - #8308 
- #10037

## Solution
- Create a `QueryBuilder` with runtime methods to define the set of
component accesses for a built query.
- Create new `WorldQueryData` implementations `FilteredEntityMut` and
`FilteredEntityRef` as variants of `EntityMut` and `EntityRef` that
provide run time checked access to the components included in a given
query.
- Add new methods to `Query` to create "query lens" with a subset of the
access of the initial query.

### Query Builder
The `QueryBuilder` API allows you to define a query at runtime. At it's
most basic use it will simply create a query with the corresponding type
signature:
```rust
let query = QueryBuilder::<Entity, With<A>>::new(&mut world).build();
// is equivalent to
let query = QueryState::<Entity, With<A>>::new(&mut world);
```
Before calling `.build()` you also have the opportunity to add
additional accesses and filters. Here is a simple example where we add
additional filter terms:
```rust
let entity_a = world.spawn((A(0), B(0))).id();
let entity_b = world.spawn((A(0), C(0))).id();

let mut query_a = QueryBuilder::<Entity>::new(&mut world)
    .with::<A>()
    .without::<C>()
    .build();
            
assert_eq!(entity_a, query_a.single(&world));
```
This alone is useful in that allows you to decide which archetypes your
query will match at runtime. However it is also very limited, consider a
case like the following:
```rust
let query_a = QueryBuilder::<&A>::new(&mut world)
// Add an additional access
    .data::<&B>()
    .build();
```
This will grant the query an additional read access to component B
however we have no way of accessing the data while iterating as the type
signature still only includes &A. For an even more concrete example of
this consider dynamic components:
```rust
let query_a = QueryBuilder::<Entity>::new(&mut world)
// Adding a filter is easy since it doesn't need be read later
    .with_id(component_id_a)
// How do I access the data of this component?
    .ref_id(component_id_b)
    .build();
```
With this in mind the `QueryBuilder` API seems somewhat incomplete by
itself, we need some way method of accessing the components dynamically.
So here's one:
### Query Transmutation
If the problem is not having the component in the type signature why not
just add it? This PR also adds transmute methods to `QueryBuilder` and
`QueryState`. Here's a simple example:
```rust
world.spawn(A(0));
world.spawn((A(1), B(0)));
let mut query = QueryBuilder::<()>::new(&mut world)
    .with::<B>()
    .transmute::<&A>()
    .build();

query.iter(&world).for_each(|a| assert_eq!(a.0, 1));
```
The `QueryState` and `QueryBuilder` transmute methods look quite similar
but are different in one respect. Transmuting a builder will always
succeed as it will just add the additional accesses needed for the new
terms if they weren't already included. Transmuting a `QueryState` will
panic in the case that the new type signature would give it access it
didn't already have, for example:
```rust
let query = QueryState::<&A, Option<&B>>::new(&mut world);
/// This is fine, the access for Option<&A> is less restrictive than &A
query.transmute::<Option<&A>>(&world);
/// Oh no, this would allow access to &B on entities that might not have it, so it panics
query.transmute::<&B>(&world);
/// This is right out
query.transmute::<&C>(&world);
```
This is quite an appealing API to also have available on `Query` however
it does pose one additional wrinkle: In order to to change the iterator
we need to create a new `QueryState` to back it. `Query` doesn't own
it's own state though, it just borrows it, so we need a place to borrow
it from. This is why `QueryLens` exists, it is a place to store the new
state so it can be borrowed when you call `.query()` leaving you with an
API like this:
```rust
fn function_that_takes_a_query(query: &Query<&A>) {
    // ...
}

fn system(query: Query<(&A, &B)>) {
    let lens = query.transmute_lens::<&A>();
    let q = lens.query();
    function_that_takes_a_query(&q);
}
```
Now you may be thinking: Hey, wait a second, you introduced the problem
with dynamic components and then described a solution that only works
for static components! Ok, you got me, I guess we need a bit more:
### Filtered Entity References
Currently the only way you can access dynamic components on entities
through a query is with either `EntityMut` or `EntityRef`, however these
can access all components and so conflict with all other accesses. This
PR introduces `FilteredEntityMut` and `FilteredEntityRef` as
alternatives that have additional runtime checking to prevent accessing
components that you shouldn't. This way you can build a query with a
`QueryBuilder` and actually access the components you asked for:
```rust
let mut query = QueryBuilder::<FilteredEntityRef>::new(&mut world)
    .ref_id(component_id_a)
    .with(component_id_b)
    .build();

let entity_ref = query.single(&world);

// Returns Some(Ptr) as we have that component and are allowed to read it
let a = entity_ref.get_by_id(component_id_a);
// Will return None even though the entity does have the component, as we are not allowed to read it
let b = entity_ref.get_by_id(component_id_b);
```
For the most part these new structs have the exact same methods as their
non-filtered equivalents.

Putting all of this together we can do some truly dynamic ECS queries,
check out the `dynamic` example to see it in action:
```
Commands:
    comp, c   Create new components
    spawn, s  Spawn entities
    query, q  Query for entities
Enter a command with no parameters for usage.

> c A, B, C, Data 4  
Component A created with id: 0
Component B created with id: 1
Component C created with id: 2
Component Data created with id: 3

> s A, B, Data 1
Entity spawned with id: 0v0

> s A, C, Data 0
Entity spawned with id: 1v0

> q &Data
0v0: Data: [1, 0, 0, 0]
1v0: Data: [0, 0, 0, 0]

> q B, &mut Data                                                                                     
0v0: Data: [2, 1, 1, 1]

> q B || C, &Data 
0v0: Data: [2, 1, 1, 1]
1v0: Data: [0, 0, 0, 0]
```
## Changelog
 - Add new `transmute_lens` methods to `Query`.
- Add new types `QueryBuilder`, `FilteredEntityMut`, `FilteredEntityRef`
and `QueryLens`
- `update_archetype_component_access` has been removed, archetype
component accesses are now determined by the accesses set in
`update_component_access`
- Added method `set_access` to `WorldQuery`, this is called before
`update_component_access` for queries that have a restricted set of
accesses, such as those built by `QueryBuilder` or `QueryLens`. This is
primarily used by the `FilteredEntity*` variants and has an empty trait
implementation.
- Added method `get_state` to `WorldQuery` as a fallible version of
`init_state` when you don't have `&mut World` access.

## Future Work
Improve performance of `FilteredEntityMut` and `FilteredEntityRef`,
currently they have to determine the accesses a query has in a given
archetype during iteration which is far from ideal, especially since we
already did the work when matching the archetype in the first place. To
avoid making more internal API changes I have left it out of this PR.

---------

Co-authored-by: Mike Hsu <mike.hsu@gmail.com>
2024-01-16 19:16:49 +00:00
vero
54a54d4c10
Remove Vec from GpuArrayBuffer (#11368)
# Objective

- Remove Vec as described in
https://github.com/bevyengine/bevy/pull/11290#issuecomment-1890315650

## Solution

- Rely on StorageBuffer's backing Vec instead

---

## Changelog

- GpuArrayBuffer no longer has a redundant backing Vec
2024-01-16 16:09:17 +00:00
Shane Celis
b6e154fc64
Fix embedded watcher to work with external crates (#11370)
# Objective

Tried using "embedded_watcher" feature and `embedded_asset!()` from
another crate. The assets embedded fine but were not "watched." The
problem appears to be that checking for the feature was done inside the
macro, so rather than checking if "embedded_watcher" was enabled for
bevy, it would check if it was enabled for the current crate.

## Solution

I extracted the checks for the "embedded_watcher" feature into its own
function called `watched_path()`. No external changes.

### Alternative Solution

An alternative fix would be to not do any feature checking in
`embedded_asset!()` or an extracted function and always send the
full_path to `insert_asset()` where it's promptly dropped when the
feature isn't turned on. That would be simpler.

```
    ($app: ident, $source_path: expr, $path: expr) => {{
        let mut embedded = $app
            .world
            .resource_mut::<$crate::io::embedded::EmbeddedAssetRegistry>();
        let path = $crate::embedded_path!($source_path, $path);
        //#[cfg(feature = "embedded_watcher")]
        let full_path = std::path::Path::new(file!()).parent().unwrap().join($path);
        //#[cfg(not(feature = "embedded_watcher"))]
        //let full_path = std::path::PathBuf::new();
        embedded.insert_asset(full_path, &path, include_bytes!($path));
    }};
```

## Changelog

> Fix embedded_watcher feature to work with external crates
2024-01-16 15:18:16 +00:00
JMS55
fcd7c0fc3d
Exposure settings (adopted) (#11347)
Rebased and finished version of
https://github.com/bevyengine/bevy/pull/8407. Huge thanks to @GitGhillie
for adjusting all the examples, and the many other people who helped
write this PR (@superdump , @coreh , among others) :)

Fixes https://github.com/bevyengine/bevy/issues/8369

---

## Changelog
- Added a `brightness` control to `Skybox`.
- Added an `intensity` control to `EnvironmentMapLight`.
- Added `ExposureSettings` and `PhysicalCameraParameters` for
controlling exposure of 3D cameras.
- Removed the baked-in `DirectionalLight` exposure Bevy previously
hardcoded internally.

## Migration Guide
- If using a `Skybox` or `EnvironmentMapLight`, use the new `brightness`
and `intensity` controls to adjust their strength.
- All 3D scene will now have different apparent brightnesses due to Bevy
implementing proper exposure controls. You will have to adjust the
intensity of your lights and/or your camera exposure via the new
`ExposureSettings` component to compensate.

---------

Co-authored-by: Robert Swain <robert.swain@gmail.com>
Co-authored-by: GitGhillie <jillisnoordhoek@gmail.com>
Co-authored-by: Marco Buono <thecoreh@gmail.com>
Co-authored-by: vero <email@atlasdostal.com>
Co-authored-by: atlas dostal <rodol@rivalrebels.com>
2024-01-16 14:53:21 +00:00
Richard Hozák
184f233a67
Use glam for computing gLTF node transform (#11361)
# Objective

gltf-rs does its own computations when accessing `transform.matrix()`
which does not use glam types, rendering #11238 useless if people were
to load gltf models and expecting the results to be deterministic across
platforms.

## Solution

Move the computation to bevy side which uses glam types, it was already
used in one place, so I created one common function to handle the two
cases.

The added benefit this has, is that some gltf files can have
translation, rotation and scale directly instead of matrix which skips
the transform computation completely, win-win.
2024-01-16 14:33:19 +00:00
Félix Lescaudey de Maneville
135c7240f1
Texture Atlas rework (#5103)
# Objective

> Old MR: #5072 
> ~~Associated UI MR: #5070~~
> Adresses #1618

Unify sprite management

## Solution

- Remove the `Handle<Image>` field in `TextureAtlas` which is the main
cause for all the boilerplate
- Remove the redundant `TextureAtlasSprite` component
- Renamed `TextureAtlas` asset to `TextureAtlasLayout`
([suggestion](https://github.com/bevyengine/bevy/pull/5103#discussion_r917281844))
- Add a `TextureAtlas` component, containing the atlas layout handle and
the section index

The difference between this solution and #5072 is that instead of the
`enum` approach is that we can more easily manipulate texture sheets
without any breaking changes for classic `SpriteBundle`s (@mockersf
[comment](https://github.com/bevyengine/bevy/pull/5072#issuecomment-1165836139))

Also, this approach is more *data oriented* extracting the
`Handle<Image>` and avoiding complex texture atlas manipulations to
retrieve the texture in both applicative and engine code.
With this method, the only difference between a `SpriteBundle` and a
`SpriteSheetBundle` is an **additional** component storing the atlas
handle and the index.

~~This solution can be applied to `bevy_ui` as well (see #5070).~~

EDIT: I also applied this solution to Bevy UI

## Changelog

- (**BREAKING**) Removed `TextureAtlasSprite`
- (**BREAKING**) Renamed `TextureAtlas` to `TextureAtlasLayout`
- (**BREAKING**) `SpriteSheetBundle`:
  - Uses a  `Sprite` instead of a `TextureAtlasSprite` component
- Has a `texture` field containing a `Handle<Image>` like the
`SpriteBundle`
- Has a new `TextureAtlas` component instead of a
`Handle<TextureAtlasLayout>`
- (**BREAKING**) `DynamicTextureAtlasBuilder::add_texture` takes an
additional `&Handle<Image>` parameter
- (**BREAKING**) `TextureAtlasLayout::from_grid` no longer takes a
`Handle<Image>` parameter
- (**BREAKING**) `TextureAtlasBuilder::finish` now returns a
`Result<(TextureAtlasLayout, Handle<Image>), _>`
- `bevy_text`:
  - `GlyphAtlasInfo` stores the texture `Handle<Image>`
  - `FontAtlas` stores the texture `Handle<Image>`
- `bevy_ui`:
- (**BREAKING**) Removed `UiAtlasImage` , the atlas bundle is now
identical to the `ImageBundle` with an additional `TextureAtlas`

## Migration Guide

* Sprites

```diff
fn my_system(
  mut images: ResMut<Assets<Image>>, 
-  mut atlases: ResMut<Assets<TextureAtlas>>, 
+  mut atlases: ResMut<Assets<TextureAtlasLayout>>, 
  asset_server: Res<AssetServer>
) {
    let texture_handle: asset_server.load("my_texture.png");
-   let layout = TextureAtlas::from_grid(texture_handle, Vec2::new(25.0, 25.0), 5, 5, None, None);
+   let layout = TextureAtlasLayout::from_grid(Vec2::new(25.0, 25.0), 5, 5, None, None);
    let layout_handle = atlases.add(layout);
    commands.spawn(SpriteSheetBundle {
-      sprite: TextureAtlasSprite::new(0),
-      texture_atlas: atlas_handle,
+      atlas: TextureAtlas {
+         layout: layout_handle,
+         index: 0
+      },
+      texture: texture_handle,
       ..Default::default()
     });
}
```
* UI


```diff
fn my_system(
  mut images: ResMut<Assets<Image>>, 
-  mut atlases: ResMut<Assets<TextureAtlas>>, 
+  mut atlases: ResMut<Assets<TextureAtlasLayout>>, 
  asset_server: Res<AssetServer>
) {
    let texture_handle: asset_server.load("my_texture.png");
-   let layout = TextureAtlas::from_grid(texture_handle, Vec2::new(25.0, 25.0), 5, 5, None, None);
+   let layout = TextureAtlasLayout::from_grid(Vec2::new(25.0, 25.0), 5, 5, None, None);
    let layout_handle = atlases.add(layout);
    commands.spawn(AtlasImageBundle {
-      texture_atlas_image: UiTextureAtlasImage {
-           index: 0,
-           flip_x: false,
-           flip_y: false,
-       },
-      texture_atlas: atlas_handle,
+      atlas: TextureAtlas {
+         layout: layout_handle,
+         index: 0
+      },
+      image: UiImage {
+           texture: texture_handle,
+           flip_x: false,
+           flip_y: false,
+       },
       ..Default::default()
     });
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François <mockersf@gmail.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
2024-01-16 13:59:08 +00:00
BD103
9f8db0de0d
Bump toml_edit in build-template-pages tool (#11342)
# Objective

- The
[`build-templated-pages`](4778fbeb65/tools/build-templated-pages)
tool is used to render the Markdown templates in the
[docs-template](4778fbeb65/docs-template)
folder.
- It depends on out outdated version of `toml_edit`.

## Solution

- Bump `toml_edit` to 0.21, disabling all features except `parse`.
2024-01-16 05:23:18 +00:00
Roman Salnikov
eb9db21113
Camera-driven UI (#10559)
# Objective

Add support for presenting each UI tree on a specific window and
viewport, while making as few breaking changes as possible.

This PR is meant to resolve the following issues at once, since they're
all related.

- Fixes #5622 
- Fixes #5570 
- Fixes #5621 

Adopted #5892 , but started over since the current codebase diverged
significantly from the original PR branch. Also, I made a decision to
propagate component to children instead of recursively iterating over
nodes in search for the root.


## Solution

Add a new optional component that can be inserted to UI root nodes and
propagate to children to specify which camera it should render onto.
This is then used to get the render target and the viewport for that UI
tree. Since this component is optional, the default behavior should be
to render onto the single camera (if only one exist) and warn of
ambiguity if multiple cameras exist. This reduces the complexity for
users with just one camera, while giving control in contexts where it
matters.

## Changelog

- Adds `TargetCamera(Entity)` component to specify which camera should a
node tree be rendered into. If only one camera exists, this component is
optional.
- Adds an example of rendering UI to a texture and using it as a
material in a 3D world.
- Fixes recalculation of physical viewport size when target scale factor
changes. This can happen when the window is moved between displays with
different DPI.
- Changes examples to demonstrate assigning UI to different viewports
and windows and make interactions in an offset viewport testable.
- Removes `UiCameraConfig`. UI visibility now can be controlled via
combination of explicit `TargetCamera` and `Visibility` on the root
nodes.

---------

Co-authored-by: davier <bricedavier@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
2024-01-16 00:39:10 +00:00
Mike
ee9a1503ed
Async channel v2 (#10692)
# Objective

- Update async channel to v2.

## Solution

- async channel doesn't support `send_blocking` on wasm anymore. So
don't compile the pipelined rendering plugin on wasm anymore.
- Replaces https://github.com/bevyengine/bevy/pull/10405

## Migration Guide
- The `PipelinedRendering` plugin is no longer exported on wasm. If you
are including it in your wasm builds you should remove it.

```rust
#[cfg(all(not(target_arch = "wasm32"))]
app.add_plugins(bevy_render::pipelined_rendering::PipelinedRenderingPlugin);
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-15 19:23:00 +00:00
Turki Al-Marri
fcc1113ec8
Fix doc of [Schedules] to mention exclusion of current schedule. (#11360)
Document that [`Schedules`] resource does not include the current
schedule.
2024-01-15 19:13:13 +00:00
Cameron
aeab690fdb
Change WinitPlugin defaults to limit game update rate when window is not visible (for real this time) (#11305)
# Objective

I goofed. #7611 forgot to change the default update modes set by the
`WinitPlugin`.


<ce5bae55f6/crates/bevy_winit/src/winit_config.rs (L53-L60)>


<ce5bae55f6/crates/bevy_winit/src/lib.rs (L127)>

## Solution

Change `Default` impl for `WinitSettings` to return the `game` settings
that limit FPS when the app runs in the background.
2024-01-15 17:53:35 +00:00
Aevyrie
839d2f8353
Approximate indirect specular occlusion (#11152)
# Objective

- The current PBR renderer over-brightens indirect specular reflections,
which tends to cause objects to appear to glow, because specular
occlusion is not accounted for.

## Solution

- Attenuate indirect specular term with an approximation for specular
occlusion, using [[Lagarde et al., 2014] (pg.
76)](https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf).

| Before | After | Animation |
| --- | --- | --- |
| <img width="1840" alt="before bike"
src="https://github.com/bevyengine/bevy/assets/2632925/b6e10d15-a998-4a94-875a-1c2b1e98348a">
| <img width="1840" alt="after bike"
src="https://github.com/bevyengine/bevy/assets/2632925/53b1479c-b1e4-427f-b140-53df26ca7193">
|
![ezgif-1-fbcbaf272b](https://github.com/bevyengine/bevy/assets/2632925/c2dece1c-eb3d-4e05-92a2-46cf83052c7c)
|
| <img width="1840" alt="classroom before"
src="https://github.com/bevyengine/bevy/assets/2632925/b16c0e74-741e-4f40-a7df-8863eaa62596">
| <img width="1840" alt="classroom after"
src="https://github.com/bevyengine/bevy/assets/2632925/26f9e971-0c63-4ee9-9544-964e5703d65e">
|
![ezgif-1-0f390edd06](https://github.com/bevyengine/bevy/assets/2632925/d8894e52-380f-4528-aa0d-1ca249108178)
|

---

## Changelog

- Ambient occlusion now applies to indirect specular reflections to
approximate how objects occlude specular light.

## Migration Guide

- Renamed `PbrInput::occlusion` to `diffuse_occlusion`, and added
`specular_occlusion`.
2024-01-15 16:10:55 +00:00
vero
4695b82f6b
Use EntityHashMap whenever possible (#11353)
# Objective

Fixes #11352

## Solution

- Use `EntityHashMap<Entity, T>` instead of `HashMap<Entity, T>`

---

## Changelog

Changed
- Use `EntityHashMap<Entity, T>` instead of `HashMap<Entity, T>`
whenever possible

## Migration Guide

TODO
2024-01-15 15:51:17 +00:00
François
3d628a8191
Fix Reactive and ReactiveLowPower update modes (#11325)
# Objective

- Partial fix for #11235 
- Fixes #11274 
- Fixes #11320 
- Fixes #11273

## Solution

- check update mode to trigger redraw request, instead of once a redraw
request has been triggered
- don't ignore device event in case of `Reactive` update mode
- make sure that at least 5 updates are triggered on application start
to ensure everything is correctly initialized
- trigger manual updates instead of relying on redraw requests when
there are no window or they are not visible
2024-01-15 15:46:11 +00:00
Félix Lescaudey de Maneville
01139b3472
Sprite slicing and tiling (#10588)
> Replaces #5213

# Objective

Implement sprite tiling and [9 slice
scaling](https://en.wikipedia.org/wiki/9-slice_scaling) for
`bevy_sprite`.
Allowing slice scaling and texture tiling.

Basic scaling vs 9 slice scaling:


![Traditional_scaling_vs_9-slice_scaling](https://user-images.githubusercontent.com/26703856/177335801-27f6fa27-c569-4ce6-b0e6-4f54e8f4e80a.svg)

Slicing example:

<img width="481" alt="Screenshot 2022-07-05 at 15 05 49"
src="https://user-images.githubusercontent.com/26703856/177336112-9e961af0-c0af-4197-aec9-430c1170a79d.png">

Tiling example:

<img width="1329" alt="Screenshot 2023-11-16 at 13 53 32"
src="https://github.com/bevyengine/bevy/assets/26703856/14db39b7-d9e0-4bc3-ba0e-b1f2db39ae8f">

# Solution

- `SpriteBundlue` now has a `scale_mode` component storing a
`SpriteScaleMode` enum with three variants:
  - `Stretched` (default) 
  - `Tiled` to have sprites tile horizontally and/or vertically
- `Sliced` allowing 9 slicing the texture and optionally tile some
sections with a `Textureslicer`.
- `bevy_sprite` has two extra systems to compute a
`ComputedTextureSlices` if necessary,:
- One system react to changes on `Sprite`, `Handle<Image>` or
`SpriteScaleMode`
- The other listens to `AssetEvent<Image>` to compute slices on sprites
when the texture is ready or changed
- I updated the `bevy_sprite` extraction stage to extract potentially
multiple textures instead of one, depending on the presence of
`ComputedTextureSlices`
- I added two examples showcasing the slicing and tiling feature.

The addition of `ComputedTextureSlices` as a cache is to avoid querying
the image data, to retrieve its dimensions, every frame in a extract or
prepare stage. Also it reacts to changes so we can have stuff like this
(tiling example):


https://github.com/bevyengine/bevy/assets/26703856/a349a9f3-33c3-471f-8ef4-a0e5dfce3b01

# Related 

- [ ] Once #5103 or #10099 is merged I can enable tiling and slicing for
texture sheets as ui

# To discuss

There is an other option, to consider slice/tiling as part of the asset,
using the new asset preprocessing but I have no clue on how to do it.

Also, instead of retrieving the Image dimensions, we could use the same
system as the sprite sheet and have the user give the image dimensions
directly (grid). But I think it's less user friendly

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
2024-01-15 15:40:06 +00:00
Cornelius
a7b99f0500
GLTF extension support (#11138)
# Objective
Adds support for accessing raw extension data of loaded GLTF assets

## Solution
Via the GLTF loader settings, you can specify whether or not to include
the GLTF source. While not the ideal way of solving this problem,
modeling all of GLTF within Bevy just for extensions adds a lot of
complexity to the way Bevy handles GLTF currently. See the example GLTF
meta file and code
```
(
    meta_format_version: "1.0",
    asset: Load(
        loader: "bevy_gltf::loader::GltfLoader",
        settings: (
            load_meshes: true,
            load_cameras: true,
            load_lights: true,
            include_source: true,
        ),
    ),
)
```
```rs
pub fn load_gltf(mut commands: Commands, assets: Res<AssetServer>) {
    let my_gltf = assets.load("test_platform.gltf");

    commands.insert_resource(MyAssetPack {
        spawned: false,
        handle: my_gltf,
    });
}

#[derive(Resource)]
pub struct MyAssetPack {
    pub spawned: bool,
    pub handle: Handle<Gltf>,
}

pub fn spawn_gltf_objects(
    mut commands: Commands,
    mut my: ResMut<MyAssetPack>,
    assets_gltf: Res<Assets<Gltf>>,
) {
    // This flag is used to because this system has to be run until the asset is loaded.
    // If there's a better way of going about this I am unaware of it.
    if my.spawned {
        return;
    }

    if let Some(gltf) = assets_gltf.get(&my.handle) {
        info!("spawn");
        my.spawned = true;
        // spawn the first scene in the file
        commands.spawn(SceneBundle {
            scene: gltf.scenes[0].clone(),
            ..Default::default()
        });

        let source = gltf.source.as_ref().unwrap();
        info!("materials count {}", &source.materials().size_hint().0);
        info!(
            "materials ext is some {}",
            &source.materials().next().unwrap().extensions().is_some()
        );
    }
}
```

---

## Changelog
Added support for GLTF extensions through including raw GLTF source via
loader flag `GltfLoaderSettings::include_source == true`, stored in
`Gltf::source: Option<gltf::Gltf>`

## Migration Guide
This will have issues with "asset migrations", as there is currently no
way for .meta files to be migrated. Attempting to migrate .meta files
without the new flag will yield the following error:
```
bevy_asset::server: Failed to deserialize meta for asset test_platform.gltf: Failed to deserialize asset meta: SpannedError { code: MissingStructField { field: "include_source", outer: Some("GltfLoaderSettings") }, position: Position { line: 9, col: 9 } }
```
This means users who want to migrate their .meta files will have to add
the `include_source: true,` setting to their meta files by hand.
2024-01-15 15:38:01 +00:00
irate
c29a9729a4
Remove the ability to ignore global volume (#11092)
# Objective

The ability to ignore the global volume doesn't seem desirable and
complicates the API.

#7706 added global volume and the ability to ignore it, but there was no
further discussion about whether that's useful. Feel free to discuss
here :)

## Solution

Replace the `Volume` type's functionality with the `VolumeLevel`. Remove
`VolumeLevel`.

I also removed `DerefMut` derive that effectively made the volume `pub`
and actually ensured that the volume isn't set below `0` even in release
builds.

## Migration Guide

The option to ignore the global volume using `Volume::Absolute` has been
removed and `Volume` now stores the volume level directly, removing the
need for the `VolumeLevel` struct.
2024-01-15 15:31:54 +00:00
Charles Bournhonesque
8c6d9b8103
Add support for updating the tracing subscriber in LogPlugin (#10822)
# Objective

This PR is heavily inspired by
https://github.com/bevyengine/bevy/pull/7682
It aims to solve the same problem: allowing the user to extend the
tracing subscriber with extra layers.

(in my case, I'd like to use `use
metrics_tracing_context::{MetricsLayer, TracingContextLayer};`)


## Solution

I'm proposing a different api where the user has the opportunity to take
the existing `subscriber` and apply any transformations on it.

---

## Changelog

- Added a `update_subscriber` option on the `LogPlugin` that lets the
user modify the `subscriber` (for example to extend it with more tracing
`Layers`


## Migration Guide

> This section is optional. If there are no breaking changes, you can
delete this section.

- Added a new field `update_subscriber` in the `LogPlugin`

---------

Co-authored-by: Charles Bournhonesque <cbournhonesque@snapchat.com>
2024-01-15 15:26:13 +00:00
Mateusz Wachowiak
8a523de8db
Describe purpose of bevy_diagnostic (#11327)
# Objective

- Explain purpose of bevy_diagnostic, see:
https://github.com/bevyengine/bevy/issues/11309#issuecomment-1889896308

## Solution

- Add doc comment
2024-01-14 20:17:26 +00:00
Torstein Grindvik
4778fbeb65
Make sure tracy deps conform to compatibility table (#11331)
# Objective

The table [here](https://github.com/nagisa/rust_tracy_client) shows
which versions of [Tracy](https://github.com/wolfpld/tracy) should be
used combined with which Rust deps.

Reading `bevy_log`'s `Cargo.toml` can be slightly confusing since the
exact versions are not picked from the same row.

Reading the produced `Cargo.lock` when building a Bevy example shows
that it's the most recent row that is resolved, but this should be more
clearly understood without needing to check the lock file.


## Solution

- Specify versions from the compatibility table including patch version

Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
2024-01-14 13:51:28 +00:00
BD103
b2d417b03d
Warn when bevy_sprite and bevy_pbr are not enabled with bevy_gizmos (#11296)
# Objective

- `bevy_gizmos` cannot work if both `bevy_sprite` and `bevy_pbr` are
disabled.
- It silently fails to render, making it difficult to debug.
- Fixes #10984

## Solution

- Log an error message when `GizmoPlugin` is registered.

## Alternatives

I chose to log an error message, since it seemed the least intrusive of
potential solutions. Some alternatives include:

- Choosing one dependency as the default, neglecting the other. (#11035)
- Raising a compile error when neither dependency is enabled. ([See my
original
comment](https://github.com/bevyengine/bevy/issues/10984#issuecomment-1873420426))
- Raising a compile warning using a macro hack. ([Pre-RFC - Add
compile_warning!
macro](https://internals.rust-lang.org/t/pre-rfc-add-compile-warning-macro/9370/7?u=bd103))
- Logging a warning instead of an error.
- _This might be the better option. Let me know if I should change it._

---

## Changelog

- `bevy_gizmos` will now log an error if neither `bevy_pbr` nor
`bevy_sprite` are enabled.
2024-01-14 13:51:14 +00:00
MiniaczQ
ec5b9eeba7
Extract examples CameraController into a module (#11338)
# Objective

Unify flycam-style camera controller from the examples.

`parallax_mapping` controller was kept as is.

## Solution

Fixed some mouse movement & cursor grabbing related issues too.
2024-01-14 13:50:33 +00:00
BD103
6f6269e195
Remove Default impl for CubicCurve (#11335)
# Objective

- Implementing `Default` for
[`CubicCurve`](https://docs.rs/bevy/latest/bevy/math/cubic_splines/struct.CubicCurve.html)
does not make sense because it cannot be mutated after creation.
- Closes #11209.
- Alternative to #11211.

## Solution

- Remove `Default` from `CubicCurve`'s derive statement.

Based off of @mockersf comment
(https://github.com/bevyengine/bevy/pull/11211#issuecomment-1880088036):

> CubicCurve can't be updated once created... I would prefer to remove
the Default impl as it doesn't make sense

---

## Changelog

- Removed the `Default` implementation for `CubicCurve`.

## Migration Guide

- Remove `CubicCurve` from any structs that implement `Default`.
- Wrap `CubicCurve` in a new type and provide your own default.

```rust
#[derive(Deref)]
struct MyCubicCurve<P: Point>(pub CubicCurve<P>);

impl Default for MyCubicCurve<Vec2> {
    fn default() -> Self {
        let points = [[
            vec2(-1.0, -20.0),
            vec2(3.0, 2.0),
            vec2(5.0, 3.0),
            vec2(9.0, 8.0),
        ]];

        Self(CubicBezier::new(points).to_curve())
    }
}
```
2024-01-14 04:40:37 +00:00
SpecificProtagonist
cd12e7c836
Make TypeId::hash more robust in case of upstream rustc changes (#11334)
Based on discussion after #11268 was merged:
Instead of panicking should the impl of `TypeId::hash` change
significantly, have a fallback and detect this in a test.
2024-01-14 04:07:14 +00:00
ickshonpe
03404c48ca
UI text rotation and scaling fix (#11326)
# Objective

UI node text is drawn in the wrong position after rotation or scaling.


![294723406-d031a3e6-a4f9-48b4-a66a-ee963100a8b9](https://github.com/bevyengine/bevy/assets/27962798/2755e2e3-6a03-4ee8-8676-bdcaa72ec678)

## Solution
In `extract_text_uinodes` to set the text's offset create a translation
matrix and multiply it by the UI node's transform.

Previously the offset was just added directly to the translation of the
Node's `GlobalTransform`, which meant no scaling or rotation would be
applied to the offset.

<img width="961" alt="296440025-537ec11c-1ea1-469c-8eec-2ad4ae012095"
src="https://github.com/bevyengine/bevy/assets/27962798/eae1a1d2-1369-47ad-8963-3862d03ec0bf">

<img width="961" alt="296440156-dd04029d-8112-4fa5-89a2-56d7acab66df"
src="https://github.com/bevyengine/bevy/assets/27962798/90b1b6db-13f4-4745-9f14-7c1661baad50">

Fixes #11241
2024-01-13 22:21:40 +00:00
Nicola Papale
a634075a39
Inline trivial methods in bevy_hierarchy (#11332)
# Objective

In #11330 I found out that `Parent::get` didn't get inlined, **even with
LTO on**!

This means that just to access a field, we have an instruction cache
invalidation, we will move some registers to the stack, will jump to new
instructions, move the field into a register, then do the same dance in
the other direction to go back to the call site.

## Solution

Mark trivial functions as `#[inline]`.

`inline(always)` may increase compilation time proportional to how many
time the function is called **and the size of the function marked with
`inline`**. Since we mark as `inline` functions that consists in a
single instruction, the cost is absolutely negligible.

I also took the opportunity to `inline` other functions. I'm not as
confident that marking functions calling other functions as `inline`
works similarly to very simple functions, so I used `inline` over
`inline(always)`, which doesn't have the same downsides as
`inline(always)`.

More information on inlining in rust:
https://nnethercote.github.io/perf-book/inlining.html
2024-01-13 22:20:50 +00:00
Nicola Papale
78b5f323f8
Skip alloc when updating animation path cache (#11330)
Not always, but skip it if the new length is smaller.

For context, `path_cache` is a `Vec<Vec<Option<Entity>>>`.

# Objective

Previously, when setting a new length to the `path_cache`, we would:

1. Deallocate all existing `Vec<Option<Entity>>`
2. Deallocate the `path_cache`
3. Allocate a new `Vec<Vec<Option<Entity>>>`, where each item is an
empty `Vec`, and would have to be allocated when pushed to.

This is a lot of allocations!

## Solution

Use
[`Vec::resize_with`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.resize_with).

With this change, what occurs is:

1. We `clear` each `Vec<Option<Entity>>`, keeping the allocation, but
making the memory of each `Vec` re-usable
2. We only append new `Vec` to `path_cache` when it is too small.

* Fixes #11328 

### Note on performance

I didn't benchmark it, I just ran a diff on the generated assembly (ran
with `--profile stress-test` and `--native`). I found this PR has 20
less instructions in `apply_animation` (out of 2504).

Though on a purely abstract level, I can deduce this leads to less
allocation.

More information on profiling allocations in rust:
https://nnethercote.github.io/perf-book/heap-allocations.html

## Future work

I think a [jagged vec](https://en.wikipedia.org/wiki/Jagged_array) would
be much more pertinent. Because it allocates everything in a single
contiguous buffer.

This would avoid dancing around allocations, and reduces the overhead of
one `*mut T` and two `usize` per row, also removes indirection,
improving cache efficiency. I think it would both improve code quality
and performance.
2024-01-13 19:33:11 +00:00
SpecificProtagonist
69760c78cf
Skip rehashing TypeIds (#11268)
# Objective

`TypeId` contains a high-quality hash. Whenever a lookup based on a
`TypeId` is performed (e.g. to insert/remove components), the hash is
run through a second hash function. This is unnecessary.

## Solution

Skip re-hashing `TypeId`s.

In my
[testing](https://gist.github.com/SpecificProtagonist/4b49ad74c6b82b0aedd3b4ea35121be8),
this improves lookup performance consistently by 10%-15% (of course, the
lookup is only a small part of e.g. a bundle insertion).
2024-01-13 13:26:43 +00:00
Alice Cecile
98b62e829d
Clean up code to find the current keyframe (#11306)
# Objective

While working on #10832, I found this code very dense and hard to
understand.

I was not confident in my fix (or the correctness of the existing code).

## Solution

Clean up, test and document the code used in the `apply_animation`
system.

I also added a pair of length-related utility methods to `Keyframes` for
easier testing. They seemed generically useful, so I made them pub.

## Changelog

- Added `VariableCurve::find_current_keyframe` method.
- Added `Keyframes::len` and `is_empty` methods.

---------

Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
2024-01-13 13:25:28 +00:00
BD103
99261232f1
Add example using State in docs (#11319)
# Objective

- It may be confusing whether
[`State`](https://docs.rs/bevy_ecs/latest/bevy_ecs/schedule/struct.State.html)
is a `Resource` or a `SystemParam`.
- Fixes #11312.

## Solution

- Add an example using `State` in a system in the docs, to clarify that
it is a `Resource`.

---

I basically copied the example from
[`States`](https://docs.rs/bevy_ecs/latest/bevy_ecs/schedule/trait.States.html)
and added a system beside it. I don't have a strong opinion on what the
example should look like, so please comment if you have a better idea.
:)
2024-01-13 13:24:00 +00:00
Ixentus
e2fd63104d
Simplify conditions (#11316)
# Objective

- Conditions don't have to be closures unless they have state or mutate.

## Solution

- Simplify conditions when possible.

---

## Changelog

The following run conditions are now regular systems:
- resource_exists<T>
- resource_added<T>
- resource_changed<T>
- resource_exists_and_changed<T>
- state_exists<S: States>
- state_changed<S: States>
- any_with_component<T: Component>

## Migration Guide

- resource_exists<T>() -> resource_exists<T>
- resource_added<T>() -> resource_added<T>
- resource_changed<T>() -> resource_changed<T>
- resource_exists_and_changed<T>() -> resource_exists_and_changed<T>
- state_exists<S: States>() -> state_exists<S: States>
- state_changed<S: States>() -> state_changed<S: States>
- any_with_component<T: Component>() -> any_with_component<T: Component>
2024-01-13 13:22:17 +00:00
Gonçalo Rica Pais da Silva
e6a324a11a
Unified identifer for entities & relations (#9797)
# Objective

The purpose of this PR is to begin putting together a unified identifier
structure that can be used by entities and later components (as
entities) as well as relationship pairs for relations, to enable all of
these to be able to use the same storages. For the moment, to keep
things small and focused, only `Entity` is being changed to make use of
the new `Identifier` type, keeping `Entity`'s API and
serialization/deserialization the same. Further changes are for
follow-up PRs.

## Solution

`Identifier` is a wrapper around `u64` split into two `u32` segments
with the idea of being generalised to not impose restrictions on
variants. That is for `Entity` to do. Instead, it is a general API for
taking bits to then merge and map into a `u64` integer. It exposes
low/high methods to return the two value portions as `u32` integers,
with then the MSB masked for usage as a type flag, enabling entity kind
discrimination and future activation/deactivation semantics.

The layout in this PR for `Identifier` is described as below, going from
MSB -> LSB.

```
|F| High value                    | Low value                      |
|_|_______________________________|________________________________|
|1| 31                            | 32                             |

F = Bit Flags
```

The high component in this implementation has only 31 bits, but that
still leaves 2^31 or 2,147,483,648 values that can be stored still, more
than enough for any generation/relation kinds/etc usage. The low part is
a full 32-bit index. The flags allow for 1 bit to be used for
entity/pair discrimination, as these have different usages for the
low/high portions of the `Identifier`. More bits can be reserved for
more variants or activation/deactivation purposes, but this currently
has no use in bevy.

More bits could be reserved for future features at the cost of bits for
the high component, so how much to reserve is up for discussion. Also,
naming of the struct and methods are also subject to further
bikeshedding and feedback.

Also, because IDs can have different variants, I wonder if
`Entity::from_bits` needs to return a `Result` instead of potentially
panicking on receiving an invalid ID.

PR is provided as an early WIP to obtain feedback and notes on whether
this approach is viable.

---

## Changelog

### Added

New `Identifier` struct for unifying IDs.

### Changed

`Entity` changed to use new `Identifier`/`IdentifierMask` as the
underlying ID logic.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: vero <email@atlasdostal.com>
2024-01-13 01:09:32 +00:00