Compare commits

...

49 Commits

Author SHA1 Message Date
François
aa80e2d658
Release: 0.13.2 2024-04-04 23:00:05 +02:00
Carter Anderson
5a82199880
Disable RAY_QUERY and RAY_TRACING_ACCELERATION_STRUCTURE by default (#12862)
# Objective

See https://github.com/gfx-rs/wgpu/issues/5488 for context and
rationale.

## Solution

- Disables `wgpu::Features::RAY_QUERY` and
`wgpu::Features::RAY_TRACING_ACCELERATION_STRUCTURE` by default. They
must be explicitly opted into now.

---

## Changelog

- Disables `wgpu::Features::RAY_QUERY` and
`wgpu::Features::RAY_TRACING_ACCELERATION_STRUCTURE` by default. They
must be explicitly opted into now.

## Migration Guide

- If you need `wgpu::Features::RAY_QUERY` or
`wgpu::Features::RAY_TRACING_ACCELERATION_STRUCTURE`, enable them
explicitly using `WgpuSettings::features`
2024-04-04 21:36:53 +02:00
Eero Lehtinen
9d03344641
Fix crash on Linux Nvidia 550 driver (#12542)
# Objective

Fix crashing on Linux with latest stable Nvidia 550 driver when
resizing. The crash happens at startup with some setups.

Fixes #12199

I think this would be nice to get into 0.13.1

## Solution

Ignore `wgpu::SurfaceError::Outdated` always on this platform+driver.

It looks like Nvidia considered the previous behaviour of not returning
this error a bug:
"Fixed a bug where vkAcquireNextImageKHR() was not returning
VK_ERROR_OUT_OF_DATE_KHR when it should with WSI X11 swapchains"
(https://www.nvidia.com/Download/driverResults.aspx/218826/en-us/)

What I gather from this is that the surface was outdated on previous
drivers too, but they just didn't report it as an error. So behaviour
shouldn't change.

In the issue conversation we experimented with calling `continue` when
this error happens, but I found that it results in some small issues
like bevy_egui scale not updating with the window sometimes. Just doing
nothing seems to work better.

## Changelog

- Fixed crashing on Linux with Nvidia 550 driver when resizing the
window

## Migration Guide

---------

Co-authored-by: James Liu <contact@jamessliu.com>
2024-04-01 23:11:59 +02:00
James Liu
03419444b6
Fix unhandled null characters in Android logs (#12743)
# Objective
Fix #12728. Fix unsoundnesss from unhandled null characters in Android
logs.

## Solution
Use `CString` instead of using formatted Strings. Properly document the
safety invariants of the FFI call.
2024-04-01 23:04:38 +02:00
François Mockers
ba1aca3b57
fix example mesh2d_manual in wasm/webgl2 (#12753)
# Objective

- Example `mesh2d_manual` crashes in wasm/webgl2, as reported in
https://github.com/bevyengine/bevy-website/issues/1123#issuecomment-2019479670
```
wgpu error: Validation Error

Caused by:
    In a RenderPass
      note: encoder = `<CommandBuffer-(0, 1, Gl)>`
    In a set_push_constant command
    Provided push constant is for stage(s) ShaderStages(VERTEX), however the pipeline layout has no push constant range for the stage(s) ShaderStages(VERTEX)
```

## Solution

- Properly declare the push constant as in
4508077297/crates/bevy_sprite/src/mesh2d/mesh.rs (L514-L524)
2024-04-01 23:04:38 +02:00
Brett Striker
be32339a32
Restore pre 0.13.1 Root Node Layout behavior (#12698)
# Objective

Fix the regression for Root Node's Layout behavior introduced in
https://github.com/bevyengine/bevy/pull/12268

- Add regression test for Root Node Layout's behaving as they did before
0.13.1
- Restore pre 0.13.1 Root Node Layout behavior (fixes
https://github.com/bevyengine/bevy/issues/12624)

## Solution

This implements [@nicoburns suggestion
](https://discord.com/channels/691052431525675048/743663673393938453/1221593626476548146),
where instead of adding the camera to the taffy node tree, we revert
back to adding a new "parent" node for each root node while maintaining
their relationship with the camera.

> If you can do the ecs change detection to move the node to the correct
Taffy instance for the camera then you should also be able to move it to
a `Vec` of root nodes for that camera.

---

## Changelog

Fixed https://github.com/bevyengine/bevy/issues/12624 - Restores pre
0.13.1 Root Node Layout behavior

## Migration Guide

If you were affected by the 0.13.1 regression and added `position_type:
Absolute` to all your root nodes you might be able to reclaim some LOC
by removing them now that the 0.13 behavior is restored.
2024-04-01 23:04:38 +02:00
Michael Allwright
1d8a7350fb
Fix fetching assets in Web Workers (#12134)
# Objective

This PR fixes #12125

## Solution

The logic in this PR was borrowed from gloo-net and essentially probes
the global Javascript context to see if we are in a window or a worker
before calling `fetch_with_str`.

---------

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2024-04-01 23:04:37 +02:00
François
55215706f2
Release: 0.13.1 2024-03-18 23:06:31 +01:00
robtfm
a66bdd074f
send Unused event when asset is actually unused (#12459)
fix #12344

use existing machinery in track_assets to determine if the asset is
unused before firing Asset::Unused event

~~most extract functions use `AssetEvent::Removed` to schedule deletion
of render world resources. `RenderAssetPlugin` was using
`AssetEvent::Unused` instead.
`Unused` fires when the last strong handle is dropped, even if a new one
is created. `Removed` only fires when a new one is not created.
as far as i can see, `Unused` is the same as `Removed` except for this
"feature", and that it also fires early if all handles for a loading
asset are dropped (`Removed` fires after the loading completes). note
that in that case, processing based on `Loaded` won't have been done
anyway.
i think we should get rid of `Unused` completely, it is not currently
used anywhere (except here, previously) and i think using it is probably
always a mistake.
i also am not sure why we keep loading assets that have been dropped
while loading, we should probably drop the loader task as well and
remove immediately.~~
2024-03-18 22:51:16 +01:00
Rob Parrett
d2e794f112
Fix CI desktop mode patch (#12440)
# Objective

The `example-showcase` command is failing to run.

```
 cargo run --release -p example-showcase -- run --screenshot --in-ci                                  
    Updating crates.io index
   Compiling example-showcase v0.14.0-dev (/Users/robparrett/src/bevy/tools/example-showcase)
    Finished release [optimized] target(s) in 2.59s
     Running `target/release/example-showcase run --screenshot --in-ci`
$ git apply --ignore-whitespace tools/example-showcase/remove-desktop-app-mode.patch
error: patch failed: crates/bevy_winit/src/winit_config.rs:29
error: crates/bevy_winit/src/winit_config.rs: patch does not apply
thread 'main' panicked at tools/example-showcase/src/main.rs:203:18:
called `Result::unwrap()` on an `Err` value: command exited with non-zero code `git apply --ignore-whitespace tools/example-showcase/remove-desktop-app-mode.patch`: 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

## Solution

Update `remove-desktop-app-mode.patch`.
2024-03-16 00:52:54 +01:00
Peter Hayman
2278c1edbb
Fix: deserialize DynamicEnum using index (#12464)
# Objective

- Addresses #12462
- When we serialize an enum, deserialize it, then reserialize it, the
correct variant should be selected.

## Solution

- Change `dynamic_enum.set_variant` to
`dynamic_enum.set_variant_with_index` in `EnumVisitor`
2024-03-16 00:32:02 +01:00
Umut
76f09e5be2
Make CreateWindowParams type and create_windows system public (#12428)
# Objective

To have a user level workaround for #12237.

## Solution

Workaround to the problem is described in:
https://github.com/bevyengine/bevy/issues/12237#issuecomment-1983680632

## Changelog

### Changed

- `CreateWindowParams` type and `create_windows` system from
`bevy_winit` is now public, which allows library authors and game
developers to manually trigger window creation when needed.
2024-03-16 00:32:02 +01:00
Rob Parrett
17005b3c8b
Fix blurry text (#12429)
# Objective

Fixes #12064

## Solution

Prior to #11326, the "global physical" translation of text was rounded.

After #11326, only the "offset" is being rounded.

This moves things around so that the "global translation" is converted
to physical pixels, rounded, and then converted back to logical pixels,
which is what I believe was happening before / what the comments above
describe.

## Discussion

This seems to work and fix an obvious mistake in some code, but I don't
fully grok the ui / text pipelines / math here.

## Before / After and test example

<details>
<summary>Expand Code</summary>

```rust
use std::f32::consts::FRAC_PI_2;

use bevy::prelude::*;
use bevy_internal:🪟:WindowResolution;

const FONT_SIZE: f32 = 25.0;
const PADDING: f32 = 5.0;

fn main() {
    App::new()
        .add_plugins(
            DefaultPlugins.set(WindowPlugin {
                primary_window: Some(Window {
                    resolution: WindowResolution::default().with_scale_factor_override(1.0),
                    ..default()
                }),
                ..default()
            }),
            //.set(ImagePlugin::default_nearest()),
        )
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2dBundle::default());

    let font = asset_server.load("fonts/FiraSans-Bold.ttf");

    for x in [20.5, 140.0] {
        for i in 1..10 {
            text(
                &mut commands,
                font.clone(),
                x,
                (FONT_SIZE + PADDING) * i as f32,
                i,
                Quat::default(),
                1.0,
            );
        }
    }

    for x in [450.5, 700.0] {
        for i in 1..10 {
            text(
                &mut commands,
                font.clone(),
                x,
                ((FONT_SIZE * 2.0) + PADDING) * i as f32,
                i,
                Quat::default(),
                2.0,
            );
        }
    }

    for y in [400.0, 600.0] {
        for i in 1..10 {
            text(
                &mut commands,
                font.clone(),
                (FONT_SIZE + PADDING) * i as f32,
                y,
                i,
                Quat::from_rotation_z(FRAC_PI_2),
                1.0,
            );
        }
    }
}

fn text(
    commands: &mut Commands,
    font: Handle<Font>,
    x: f32,
    y: f32,
    i: usize,
    rot: Quat,
    scale: f32,
) {
    let text = (65..(65 + i)).map(|a| a as u8 as char).collect::<String>();

    commands.spawn(TextBundle {
        style: Style {
            position_type: PositionType::Absolute,
            left: Val::Px(x),
            top: Val::Px(y),
            ..default()
        },
        text: Text::from_section(
            text,
            TextStyle {
                font,
                font_size: FONT_SIZE,
                ..default()
            },
        ),
        transform: Transform::from_rotation(rot).with_scale(Vec2::splat(scale).extend(1.)),
        ..default()
    });
}
```

</details>

Open both images in new tabs and swap back and forth. Pay attention to
the "A" and "ABCD" lines.

<details>
<summary>Before</summary>

<img width="640" alt="main3"
src="https://github.com/bevyengine/bevy/assets/200550/248d7a55-d06d-433f-80da-1914803c3551">

</details>

<details>
<summary>After</summary>

<img width="640" alt="pr3"
src="https://github.com/bevyengine/bevy/assets/200550/26a9d292-07ae-4af3-b035-e187b2529ace">

</details>

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
2024-03-13 08:23:38 +01:00
Eira Fransham
9f24bd8705
SystemId should manually implement Eq (#12436)
# Objective

`System<f32>` currently does not implement `Eq` even though it should

## Solution

Manually implement `Eq` like other traits are manually implemented
2024-03-13 08:23:38 +01:00
robtfm
3b97fd625a
don't attempt to set cursor relative position for zero sized nodes (#12395)
# Objective

fix #12007

## Solution

when node size is zero on either axis, set
`RelativeCursorPosition::normalized` to None.
2024-03-10 08:45:13 +01:00
robtfm
5c6628fe3c
try_insert NoAutomaticBatching (#12396)
# Objective

fix occasional crash from commands.insert when quickly spawning and
despawning skinned/morphed meshes
 
## Solution

use `try_insert` instead of `insert`. if the entity is deleted we don't
mind failing to add the `NoAutomaticBatching` marker.
2024-03-10 08:45:13 +01:00
Antony
cc153ec930 Fix gizmos panicking given bad output from GlobalTransform::to_scale_rotation_translation (#12375)
# Objective

Fixes #12360.

## Solution

Normalize the rotation `Quat` in `sphere`.
2024-03-08 08:11:18 +01:00
BD103
3c3241a803 Improve Bloom 3D lighting (#11981)
- With the recent lighting changes, the default configuration in the
`bloom_3d` example is less clear what bloom actually does
- See [this
screenshot](4fdb1455d5 (r1494648414))
for a comparison.
- `bloom_3d` additionally uses a for-loop to spawn the spheres, which
can be turned into `commands::spawn_batch` call.
- The text is black, which is difficult to see on the gray background.

- Increase emmisive values of materials.
- Set text to white.

Before:

<img width="1392" alt="before"
src="https://github.com/bevyengine/bevy/assets/59022059/757057ad-ed9f-4eed-b135-8e2032fcdeb5">

After:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/3f9dc7a8-94b2-44b9-8ac3-deef1905221b">

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-03-08 08:11:18 +01:00
Rob Parrett
0767e62112 Fix ImageLoader not being initialized with webp or pnm features (#12355)
# Objective

Fixes #12353

When only `webp` was selected, `ImageLoader` would not be initialized.

That is, users using `default-features = false` would need to add `png`
or `bmp` or something in addition to `webp` in order to use `webp`.

This was also the case for `pnm`. 

## Solution

Add `webp` and `pnm` to the list of features that trigger the
initialization of `ImageLoader`.
2024-03-08 07:46:37 +01:00
vero
2683dfeee8 Fix directional light shadow frustum culling near clip plane to infinity (#12342)
# Objective

- Fix slightly wrong logic from #11442
- Directional lights should not have a near clip plane

## Solution

- Push near clip out to infinity, so that the frustum normal is still
available if its needed for whatever reason in shader
- also opportunistically nabs a typo
2024-03-08 07:46:37 +01:00
Antony
6e6e99efdd Fix with_scale_factor_override improperly setting scale_factor_override (#12321)
# Objective

Fixes #12282.

## Solution

Use `set_scale_factor_override` in `with_scale_factor_override`.
2024-03-05 22:10:50 +01:00
François
7f9ebfd603 don't depend directly on oboe (#12316)
- Avoid version mismatch
- When cpal updates oboe in a patch release, this breaks android support
for Bevy

- Use the same version of oboe as cpal by relying on it to re-export the
feature
2024-03-05 22:10:50 +01:00
Brett Striker
cb76dbbe97 Fix #12255 Updating TargetCamera on multi camera scenes not allowing layout to be calculated (#12268)
# Objective

- Fixes #12255

Still needs confirming what the consequences are from having camera
viewport nodes live on the root of the taffy tree.

## Solution

To fix calculating the layouts for UI nodes we need to cleanup the
children previously set whenever `TargetCamera` is updated. This also
maintains a list of taffy camera nodes and cleans them up when removed.

---

## Changelog

Fixed #12255

## Migration Guide

changes affect private structs/members so shouldn't need actions by
engine users.
2024-03-05 22:10:30 +01:00
thebluefish
54f0c556f6 Fix winit control flow when re-focusing game (#12239)
# Objective

Fixes #12126

Notably this does not appear to fix the console error spam that appears
to be coming from winit, only the performance bug that occurs when
tabbing out and back into the game.

## Solution

The winit event loop starts out as `ControlFlow::Wait` by default. When
switching to `UpdateMode::Reactive` or `UpdateMode::ReactiveLowPower`,
we repeatedly update this to `ControlFlow::WaitUntil(next)`. When
switching back to `UpdateMode::Continuous`, the event loop is
erroneously stuck at the latest `ControlFlow::WaitUntil(next)` that was
issued.

I also changed how we handle `Event::NewEvents` since the `StartCause`
already tells us enough information to make that decision. This came
about my debugging and I left it in as an improvement.
2024-03-05 22:10:30 +01:00
Robin Kellner
db9d84fb2f Add the ability to request a redraw from an external source (#12197)
Hi, this is a minimal implementation of #12159. I wasn't sure if the
`EventLoopProxy` should be wrapped somewhat to make it more explicit.

Minimal implementation of #12159
When using `UpdateMode::Reactive` it is currently not possible to
request a redraw when a long running task is finished or an external
source has new data.

This makes the following possible which will then run an app update once

``` rust
// EventLoopProxy is Send on most architectures
// The EventLoopProxy can also be saved in a thread local for WASM or a static in other architecturecs
pub fn example(proxy: NonSend<EventLoopProxy<()>>) {
    let clone: EventLoopProxy<()> = proxy.clone();
    thread::spawn(move || {
        // do long work
        clone.send_event(());
    });
}
```

By using the EventLoopProxy one can manually send events from external
threads to the event loop as `UserEvent`s.
This simply sets redraw_requested when a `UserEvent` is received.

- Added the ability to request a redraw from an external source

---------

Co-authored-by: Kellner, Robin <Robin.Kellner@vector.com>
2024-03-05 22:10:30 +01:00
Kaur Kuut
f4df8b8545 Update wgpu to v0.19.3 and unpin web-sys. (#12247)
This PR unpins `web-sys` so that unrelated projects that have
`bevy_render` in their workspace can finally update their `web-sys`.
More details in and fixes #12246.

* Update `wgpu` from 0.19.1 to 0.19.3.
* Remove the `web-sys` pin.
* Update docs and wasm helper to remove the now-stale
`--cfg=web_sys_unstable_apis` Rust flag.

---

Updated `wgpu` to v0.19.3 and removed `web-sys` pin.
2024-03-02 07:44:53 +01:00
François
7caa026806 configure_surface needs to be on the main thread on iOS (#12055)
# Objective

- Bevy fails to change screen orientation on iOS
```
Main Thread Checker: UI API called on a background thread: -[UIView layer]
PID: 37669, TID: 13872050, Thread name: Compute Task Pool (1), Queue name: com.apple.root.default-qos.overcommit, QoS: 0
Backtrace:
4   bevy_mobile_example                 0x0000000102cf92b8 _ZN60_$LT$$LP$$RP$$u20$as$u20$objc..message..MessageArguments$GT$6invoke17h8944e3d8ee34f15fE + 64
5   bevy_mobile_example                 0x0000000102c46358 _ZN4objc7message8platform15send_unverified17h667844cebe2d7931E + 132
6   bevy_mobile_example                 0x0000000102bcbd6c _ZN8wgpu_hal5metal7surface100_$LT$impl$u20$wgpu_hal..Surface$LT$wgpu_hal..metal..Api$GT$$u20$for$u20$wgpu_hal..metal..Surface$GT$9configure17h8a6af0f24cec1328E + 1548
7   bevy_mobile_example                 0x000000010279be50 _ZN9wgpu_core6device6global52_$LT$impl$u20$wgpu_core..global..Global$LT$G$GT$$GT$17surface_configure17h52709bbb3b3f0ff1E + 2792
8   bevy_mobile_example                 0x000000010287aacc _ZN84_$LT$wgpu..backend..wgpu_core..ContextWgpuCore$u20$as$u20$wgpu..context..Context$GT$17surface_configure17h54077b9f040286a4E + 508
9   bevy_mobile_example                 0x00000001028904b4 _ZN47_$LT$T$u20$as$u20$wgpu..context..DynContext$GT$17surface_configure17hfd6a0ac5a67a8f02E + 256
10  bevy_mobile_example                 0x00000001028a1870 _ZN4wgpu7Surface9configure17h97bf7dbd54220473E + 148
11  bevy_mobile_example                 0x0000000101fdc7cc _ZN11bevy_render8renderer13render_device12RenderDevice17configure_surface17h6853eab840b53e07E + 56
12  bevy_mobile_example                 0x000000010228eb64 _ZN11bevy_render4view6window15prepare_windows17hf6f8b3c93ba189b8E + 3248
13  bevy_mobile_example                 0x0000000102169eb8 _ZN4core3ops8function5FnMut8call_mut17h53ae762930afec98E + 192
14  bevy_mobile_example                 0x0000000101e46a80 _ZN4core3ops8function5impls79_$LT$impl$u20$core..ops..function..FnMut$LT$A$GT$$u20$for$u20$$RF$mut$u20$F$GT$8call_mut17h5789c37c5983ce4cE + 208
15  bevy_mobile_example                 0x0000000101e936e4 _ZN152_$LT$Func$u20$as$u20$bevy_ecs..system..function_system..SystemParamFunction$LT$fn$LP$F0$C$F1$C$F2$C$F3$C$F4$C$F5$C$F6$C$F7$RP$$u20$.$GT$$u20$Out$GT$$GT$3run10call_inner17h4ea44d3456146151E + 220
16  bevy_mobile_example                 0x0000000101e4683c _ZN152_$LT$Func$u20$as$u20$bevy_ecs..system..function_system..SystemParamFunction$LT$fn$LP$F0$C$F1$C$F2$C$F3$C$F4$C$F5$C$F6$C$F7$RP$$u20$.$GT$$u20$Out$GT$$GT$3run17h6515ba9e61bb4d59E + 204
17  bevy_mobile_example                 0x0000000101e7f99c _ZN120_$LT$bevy_ecs..system..function_system..FunctionSystem$LT$Marker$C$F$GT$$u20$as$u20$bevy_ecs..system..system..System$GT$10run_unsafe17h78999ea2add1da26E + 212
18  bevy_mobile_example                 0x0000000103b4ef60 _ZN8bevy_ecs8schedule8executor14multi_threaded21MultiThreadedExecutor17spawn_system_task28_$u7b$$u7b$closure$u7d$$u7d$28_$u7b$$u7b$closure$u7d$$u7d$17hb2572f7968d8618eE + 48
19  bevy_mobile_example                 0x0000000103b5bc9c _ZN4core3ops8function6FnOnce9call_once17h4cfa9d5c488566d4E + 16
20  bevy_mobile_example                 0x0000000103b2d58c _ZN115_$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$9call_once17he61d5557ff370a2cE + 40
21  bevy_mobile_example                 0x0000000103b34548 _ZN3std9panicking3try7do_call17hb9ad087e1a06eb39E + 72
22  bevy_mobile_example                 0x0000000103b351bc __rust_try + 32
23  bevy_mobile_example                 0x0000000103b33a30 _ZN3std9panicking3try17hdebf82084f4342b0E + 76
24  bevy_mobile_example                 0x0000000103c4aedc _ZN3std5panic12catch_unwind17h7e60b22a0a18032eE + 12
25  bevy_mobile_example                 0x0000000103b4ea78 _ZN8bevy_ecs8schedule8executor14multi_threaded21MultiThreadedExecutor17spawn_system_task28_$u7b$$u7b$closure$u7d$$u7d$17h1af950387501b795E + 148
26  bevy_mobile_example                 0x0000000103b2cfa0 _ZN100_$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..future..future..Future$GT$4poll17h1258e4bf3dbe2fd8E + 48
```

## Solution

- run surface configuration on the main thread on iOS

## Migration Guide

System `need_new_surfaces` has been renamed `need_surface_configuration`
and now also configure the surfaces on window creation or resizing
2024-03-01 00:09:18 +01:00
Sludge
b8c58dedd9 Avoid panicking with non-UI nodes (#12213)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/10826
- Fixes https://github.com/bevyengine/bevy/issues/9615

## Solution

- Early-out when components are missing.
2024-03-01 00:09:18 +01:00
François
8234978ab0 add note about unloading assets from ram in wasm (#12166)
# Objective

- Fixes #12057 

## Solution

- Add a note about memory management in Wasm
2024-02-28 07:05:02 +01:00
Sludge
faa1387720 Reflect GizmoConfigStore (#12104)
# Objective

- Make `GizmoConfigStore` play well with reflection-based workflows like
editors.

## Solution

- `#[derive(Reflect)]` and call `.register_type()`.
2024-02-27 17:17:54 +01:00
SpecificProtagonist
d6e6814ac3 Fix SimpleExecutor crash (#12076)
# Objective

Since #9822, `SimpleExecutor` panics when an automatic sync point is
inserted:

```rust
let mut sched = Schedule::default();
sched.set_executor_kind(ExecutorKind::Simple);
sched.add_systems((|_: Commands| (), || ()).chain());
sched.run(&mut World::new());
```
```
System's param_state was not found. Did you forget to initialize this system before running it?
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_ecs::schedule::executor::apply_deferred`!
```

## Solution

Don't try to run the `apply_deferred` system.
2024-02-27 17:17:54 +01:00
Waridley
b1f061586d Pad SkyUniforms to 16 bytes for WASM (#12078)
# Objective

Fixes Skyboxes on WebGL, which broke in Bevy 0.13 due to the addition of
the `brightness` uniform, when previously the skybox pipeline only had
view and global uniforms.

```ignore
panicked at ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.1/src/backend/wgpu_core.rs:3009:5:
wgpu error: Validation Error

Caused by:
    In Device::create_render_pipeline
      note: label = `skybox_pipeline`
    In the provided shader, the type given for group 0 binding 3 has a size of 4. As the device does not support `DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED`, the type must have a size that is a multiple of 16 bytes.
```

It would be nice if this could be backported to a 0.13.1 patch as well
if possible. I'm needing to rely on my own fork for now.

## Solution

Similar to the Globals uniform solution here:


d31de3f139/crates/bevy_render/src/globals.rs (L59-L60)

I've added 3 conditional fields to `SkyboxUniforms`.
2024-02-27 17:17:54 +01:00
Doonv
784b9bd945 Remove unnecessary wildcards from LogPlugin and convert warnings to errors. (#12046)
# Objective

Improve code quality and prevent bugs.

## Solution

I removed the unnecessary wildcards from `<LogPlugin as Plugin>::build`.

I also changed the warnings that would occur if the subscriber/logger
was already set into errors.
2024-02-27 17:17:54 +01:00
François
5bf5d48759 set pipeline to queued when shader is not yet available (#12051)
# Objective

- Fixes #11977 - user defined shaders don't work in wasm
- After investigation, it won't work if the shader is not yet available
when compiling the pipeline on all platforms, for example if you load
many assets

## Solution

- Set the pipeline state to queued when it errs waiting for the shader
so that it's retried
2024-02-27 17:17:54 +01:00
IceSentry
d62319be38 Make more things pub in the renderer (#12053)
# Objective

- Some properties of public types are private but sometimes it's useful
to be able to set those

## Solution

- Make more stuff pub

---

## Changelog

- `MaterialBindGroupId` internal id is now pub and added a new()
constructor
- `ExtractedPointLight` and `ExtractedDirectionalLight` properties are
now all pub

---------

Co-authored-by: James Liu <contact@jamessliu.com>
2024-02-27 17:17:54 +01:00
Sam Pettersson
a8fa1f77b9 FIX: iOS Simulator not rendering due to missing CUBE_ARRAY_TEXTURES (#12052)
This PR closes #11978

# Objective

Fix rendering on iOS Simulators.

iOS Simulator doesn't support the capability CUBE_ARRAY_TEXTURES, since
0.13 this started to make iOS Simulator not render anything with the
following message being outputted:

```
2024-02-19T14:59:34.896266Z ERROR bevy_render::render_resource::pipeline_cache: failed to create shader module: Validation Error

Caused by:
    In Device::create_shader_module
    
Shader validation error: 


    Type [40] '' is invalid
    Capability Capabilities(CUBE_ARRAY_TEXTURES) is required
```

## Solution

- Split up NO_ARRAY_TEXTURES_SUPPORT into both NO_ARRAY_TEXTURES_SUPPORT
and NO_CUBE_ARRAY_TEXTURES_SUPPORT and correctly apply
NO_ARRAY_TEXTURES_SUPPORT for iOS Simulator using the cfg flag
introduced in #10178.

---

## Changelog

### Fixed
- Rendering on iOS Simulator due to missing CUBE_ARRAY_TEXTURES support.

---------

Co-authored-by: Sam Pettersson <sam.pettersson@geoguessr.com>
2024-02-27 17:17:54 +01:00
Félix Lescaudey de Maneville
0e75d0066e Fixed Ui Image slicing (#12047)
# Objective

Fixes #11944

## Solution

#11600 made an incorrect assumption on what `UiImageSize` does, removing
its usage in slicing fixes the problem
2024-02-27 17:17:54 +01:00
Jakob Hellermann
4022385f51 Fix SystemTypeSet::system_type being out of sync with System::type_id (#12030)
## Objective

Always have `some_system.into_system().type_id() ==
some_system.into_system_set().system_type().unwrap()`.

System sets have a `fn system_type() -> Option<TypeId>` that is
implemented by `SystemTypeSet` to returning the TypeId of the system's
function type. This was implemented in
https://github.com/bevyengine/bevy/pull/7715 and is used in
`bevy_mod_debugdump` to handle `.after(function)` constraints.

Back then, `System::type_id` always also returned the type id of the
function item, not of `FunctionSystem<M, F>`.

https://github.com/bevyengine/bevy/pull/11728 changes the behaviour of
`System::type_id` so that it returns the id of the
`FunctionSystem`/`ExclusiveFunctionSystem` wrapper, but it did not
change `SystemTypeSet::system_type`, so doing the lookup breaks in
`bevy_mod_debugdump`.

## Solution

Change `IntoSystemSet` for functions to return a
`SystemTypeSet<FunctionSystem>` /
`SystemTypeSet<ExclusiveFunctionSystem>` instead of `SystemTypeSet<F>`.
2024-02-27 17:17:54 +01:00
IceSentry
48d93b8e68 Make Globals visible in vertex shaders (#12032)
# Objective

- Globals are supposed to be available in vertex shader but that was
mistakenly removed in 0.13

## Solution

- Configure the visibility of the globals correctly

Fixes https://github.com/bevyengine/bevy/issues/12015
2024-02-27 17:17:53 +01:00
BD103
f268c69402 Improve lighting in more examples (#12021)
- #11868 changed the lighting system, forcing lights to increase their
intensity. The PR fixed most examples, but missed a few. These I later
caught in https://github.com/bevyengine/bevy-website/pull/1023.
- Related: #11982, #11981.
- While there, I noticed that the spotlight example could use a few easy
improvements.

- Increase lighting in `skybox`, `spotlight`, `animated_transform`, and
`gltf_skinned_mesh`.
- Improve spotlight example.
- Make ground plane move with cubes, so they don't phase into each
other.
  - Batch spawn cubes.
  - Add controls text.
  - Change controls to allow rotating around spotlights.

Before:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/8ba00d74-6d68-4414-97a8-28afb8305570">

After:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/ad15c471-6979-4dda-9889-9189136d8404">

Before:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/53f966de-acf3-46b8-8299-0005c4cb8da0">

After:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/05c73c1e-0739-4226-83d6-e4249a9105e0">

Before:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/6d7d4ea0-e22e-42a5-9905-ea1731d474cf">

After:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/f1ee08d6-d17a-4391-91a6-d903b9fbdc3c">

Before:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/547569a6-d13b-4fe0-a8c1-e11f02c4f9a2">

After:

<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/34517aba-09e4-4e9b-982a-a4a8b893c48a">

---

- Increased lighting in `skybox`, `spotlight`, `animated_transform`, and
`gltf_skinned_mesh` examples.
- Improved usability of `spotlight` example.
2024-02-27 17:14:31 +01:00
radiish
6b26a41a9d reflect: treat proxy types correctly when serializing (#12024)
# Objective

- Fixes #12001.
- Note this PR doesn't change any feature flags, however flaky the issue
revealed they are.

## Solution

- Use `FromReflect` to convert proxy types to concrete ones in
`ReflectSerialize::get_serializable`.
- Use `get_represented_type_info() -> type_id()` to get the correct type
id to interact with the registry in
`bevy_reflect::serde::ser::get_serializable`.

---

## Changelog

- Registering `ReflectSerialize` now imposes additional `FromReflect`
and `TypePath` bounds.

## Migration Guide

- If `ReflectSerialize` is registered on a type, but `TypePath` or
`FromReflect` implementations are omitted (perhaps by
`#[reflect(type_path = false)` or `#[reflect(from_reflect = false)]`),
the traits must now be implemented.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-02-27 17:12:51 +01:00
BD103
bbd38e735f Increase 3D Lighting example's light intensity (#11982)
- The 3D Lighting example is meant to show using multiple lights in the
same scene.
- It currently looks very dark. (See [this
image](4fdb1455d5 (r1494653511)).)
- Resetting the physical camera properties sets the shutter speed to 1 /
125, even though it initially starts at 1 / 100.

- Increase the intensity of all 3 lights in the example.
  - Now it is much closer to the example in Bevy 0.12.
- I had to remove the comment explaining the lightbulb equivalent of the
intensities because I don't know how it was calculated. Does anyone know
what light emits 100,000 lumens?
- Set the initial shutter speed to 1 / 125.

Before:

<img width="1392" alt="before"
src="https://github.com/bevyengine/bevy/assets/59022059/ac353e02-58e9-4661-aa6d-e5fdf0dcd2f6">

After:

<img width="1392" alt="after"
src="https://github.com/bevyengine/bevy/assets/59022059/4ff0beb6-0ced-4fb2-a953-04be2c77f437">

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-27 17:12:51 +01:00
Yutao Yuan
4e24b68fa6 Create imported_assets directory with full path (#12022)
# Objective

- The file asset source currently creates the `imported_assets/Default`
directory with relative path, which leads to wrongly created directories
when the executable is run with a working directory different from the
project root.

## Solution

- Use the full path instead.
2024-02-27 17:11:42 +01:00
Robin KAY
152ee42a72 Fix MSAA writeback when 3 or more cameras have the same target. (#11968)
# Objective

If multiple cameras render to the same target with MSAA enabled, only
the first and the last camera output will appear in the final output*.
This is because each camera maintains a separate flag to track the
active main texture. The first camera renders to texture A and all
subsequent cameras first write-back from A and then render into texture
B. Hence, camera 3 onwards will overwrite the work of the previous
camera.

\* This would manifest slightly differently if there were other calls to
post_process_write() in a more complex setup.

The is a functional regression from Bevy 0.12.

## Solution

The flag which tracks the active main texture should be shared between
cameras with the same `NormalizedRenderTarget`. Add the
`Arc<AtomicUsize>` to the existing per-target cache.
2024-02-27 17:11:42 +01:00
David M. Lary
5d9c9b85d5 Stepping disabled performance fix (#11959)
# Objective

* Fixes #11932 (performance impact when stepping is disabled)

## Solution

The `Option<FixedBitSet>` argument added to `ScheduleExecutor::run()` in
#8453 caused a measurable performance impact even when stepping is
disabled. This can be seen by the benchmark of running `Schedule:run()`
on an empty schedule in a tight loop
(https://github.com/bevyengine/bevy/issues/11932#issuecomment-1950970236).

I was able to get the same performance results as on 0.12.1 by changing
the argument
`ScheduleExecutor::run()` from `Option<FixedBitSet>` to
`Option<&FixedBitSet>`. The down-side of this change is that
`Schedule::run()` now takes about 6% longer (3.7319 ms vs 3.9855ns) when
stepping is enabled

---

## Changelog
* Change `ScheduleExecutor::run()` `_skipped_systems` from
`Option<FixedBitSet>` to `Option<&FixedBitSet>`
* Added a few benchmarks to measure `Schedule::run()` performance with
various executors
2024-02-27 17:11:42 +01:00
andriyDev
2a3e367b82 Add the serde feature to bitflags for bevy_render. (#11966)
# Objective

Fixes #11964.

## Solution

Adds the `serde` feature to `bitflags` for `bevy_render`. This makes
`bevy_render` compile correctly when used alone.

---

## Changelog

- Fixed an issue where depending on `bevy_render` alone would fail to
compile.
2024-02-27 17:11:42 +01:00
TimJentzsch
1e57ca6f5e Fix dds feature dependencies in bevy_core_pipeline (#11962)
# Objective

- Fixes #11960
- The compilation of `bevy_core_pipeline` failed with the `dds` feature
enabled

## Solution

- Enable the `dds` feature of `bevy_render` when enabling it for
`bevy_core_pipeline`
2024-02-27 17:11:42 +01:00
Andrew
b46c11c134 revert PointLightBundle to DirectionalLightBundle change made to asset_loading example between 0.12.1 and 0.13.0 (#11935)
# Objective

- revert a single-line change made to `examples/asset/asset_loading`
example between `v0.12.1` release and `v0.13.0` release which resulted
in a too-bright, washed-out rendering

## Solution

- reverted the changes made to this example between `v0.12.1` and
`v0.13.0`
2024-02-27 17:11:42 +01:00
Carter Anderson
63a3da8703 Add bevy_gizmos/macros to publish script (#11928)
# Objective

This crate is needed if we want to successfully publish other Bevy
crates (hint: we do!)
2024-02-27 17:11:42 +01:00
113 changed files with 1343 additions and 823 deletions

View File

@ -142,8 +142,6 @@ jobs:
target: wasm32-unknown-unknown
- name: Check wasm
run: cargo check --target wasm32-unknown-unknown
env:
RUSTFLAGS: --cfg=web_sys_unstable_apis
markdownlint:
runs-on: ubuntu-latest

View File

@ -1,6 +1,6 @@
[package]
name = "bevy"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
categories = ["game-engines", "graphics", "gui", "rendering"]
description = "A refreshingly simple data-driven game engine and app framework"
@ -289,7 +289,7 @@ pbr_transmission_textures = ["bevy_internal/pbr_transmission_textures"]
# Enable some limitations to be able to use WebGL2. Please refer to the [WebGL2 and WebGPU](https://github.com/bevyengine/bevy/tree/latest/examples#webgl2-and-webgpu) section of the examples README for more information on how to run Wasm builds with WebGPU.
webgl2 = ["bevy_internal/webgl"]
# Enable support for WebGPU in Wasm. When enabled, this feature will override the `webgl2` feature and you won't be able to run Wasm builds with WebGL2, only with WebGPU. Requires the `RUSTFLAGS` environment variable to be set to `--cfg=web_sys_unstable_apis` when building.
# Enable support for WebGPU in Wasm. When enabled, this feature will override the `webgl2` feature and you won't be able to run Wasm builds with WebGL2, only with WebGPU.
webgpu = ["bevy_internal/webgpu"]
# Enables the built-in asset processor for processed assets.
@ -305,8 +305,8 @@ embedded_watcher = ["bevy_internal/embedded_watcher"]
bevy_debug_stepping = ["bevy_internal/bevy_debug_stepping"]
[dependencies]
bevy_dylib = { path = "crates/bevy_dylib", version = "0.13.0", default-features = false, optional = true }
bevy_internal = { path = "crates/bevy_internal", version = "0.13.0", default-features = false }
bevy_dylib = { path = "crates/bevy_dylib", version = "0.13.2", default-features = false, optional = true }
bevy_internal = { path = "crates/bevy_internal", version = "0.13.2", default-features = false }
[dev-dependencies]
rand = "0.8.0"

View File

@ -19,4 +19,5 @@ criterion_group!(
contrived,
schedule,
build_schedule,
empty_schedule_run,
);

View File

@ -118,3 +118,28 @@ pub fn build_schedule(criterion: &mut Criterion) {
group.finish();
}
pub fn empty_schedule_run(criterion: &mut Criterion) {
let mut app = bevy_app::App::default();
let mut group = criterion.benchmark_group("run_empty_schedule");
let mut schedule = Schedule::default();
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
group.bench_function("SingleThreaded", |bencher| {
bencher.iter(|| schedule.run(&mut app.world));
});
let mut schedule = Schedule::default();
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::MultiThreaded);
group.bench_function("MultiThreaded", |bencher| {
bencher.iter(|| schedule.run(&mut app.world));
});
let mut schedule = Schedule::default();
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::Simple);
group.bench_function("Simple", |bencher| {
bencher.iter(|| schedule.run(&mut app.world));
});
group.finish();
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_a11y"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides accessibility support for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,9 +10,9 @@ keywords = ["bevy", "accessibility", "a11y"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
accesskit = "0.12"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_animation"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides animation functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,19 +10,19 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_time = { path = "../bevy_time", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_time = { path = "../bevy_time", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_app"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides core App functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -17,11 +17,11 @@ bevy_reflect = ["dep:bevy_reflect", "bevy_ecs/bevy_reflect"]
[dependencies]
# bevy
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
# other
serde = { version = "1.0", features = ["derive"], optional = true }

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_asset"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides asset functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -18,13 +18,13 @@ asset_processor = []
watch = []
[dependencies]
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset_macros = { path = "macros", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset_macros = { path = "macros", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
async-broadcast = "0.5"
async-fs = "2.0"
@ -40,7 +40,7 @@ serde = { version = "1", features = ["derive"] }
thiserror = "1.0"
[target.'cfg(target_os = "android")'.dependencies]
bevy_winit = { path = "../bevy_winit", version = "0.13.0" }
bevy_winit = { path = "../bevy_winit", version = "0.13.2" }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }
@ -52,7 +52,7 @@ js-sys = "0.3"
notify-debouncer-full = { version = "0.3.1", optional = true }
[dev-dependencies]
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_asset_macros"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Derive implementations for bevy_asset"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.2" }
syn = "2.0"
proc-macro2 = "1.0"

View File

@ -503,10 +503,8 @@ impl<A: Asset> Assets<A> {
while let Ok(drop_event) = assets.handle_provider.drop_receiver.try_recv() {
let id = drop_event.id.typed();
assets.queued_events.push(AssetEvent::Unused { id });
if drop_event.asset_server_managed {
let untyped_id = drop_event.id.untyped(TypeId::of::<A>());
let untyped_id = id.untyped();
if let Some(info) = infos.get(untyped_id) {
if info.load_state == LoadState::Loading
|| info.load_state == LoadState::NotLoaded
@ -515,12 +513,16 @@ impl<A: Asset> Assets<A> {
continue;
}
}
if infos.process_handle_drop(untyped_id) {
assets.remove_dropped(id);
// the process_handle_drop call checks whether new handles have been created since the drop event was fired, before removing the asset
if !infos.process_handle_drop(untyped_id) {
// a new handle has been created, or the asset doesn't exist
continue;
}
} else {
assets.remove_dropped(id);
}
assets.queued_events.push(AssetEvent::Unused { id });
assets.remove_dropped(id);
}
// TODO: this is _extremely_ inefficient find a better fix

View File

@ -75,16 +75,15 @@ impl FileAssetWriter {
///
/// See `get_base_path` below.
pub fn new<P: AsRef<Path> + std::fmt::Debug>(path: P, create_root: bool) -> Self {
let root_path = get_base_path().join(path.as_ref());
if create_root {
if let Err(e) = std::fs::create_dir_all(&path) {
if let Err(e) = std::fs::create_dir_all(&root_path) {
error!(
"Failed to create root directory {:?} for file asset writer: {:?}",
path, e
root_path, e
);
}
}
Self {
root_path: get_base_path().join(path.as_ref()),
}
Self { root_path }
}
}

View File

@ -5,10 +5,25 @@ use bevy_log::error;
use bevy_utils::BoxedFuture;
use js_sys::{Uint8Array, JSON};
use std::path::{Path, PathBuf};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
use web_sys::Response;
/// Represents the global object in the JavaScript context
#[wasm_bindgen]
extern "C" {
/// The [Global](https://developer.mozilla.org/en-US/docs/Glossary/Global_object) object.
type Global;
/// The [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) global object.
#[wasm_bindgen(method, getter, js_name = Window)]
fn window(this: &Global) -> JsValue;
/// The [WorkerGlobalScope](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope) global object.
#[wasm_bindgen(method, getter, js_name = WorkerGlobalScope)]
fn worker(this: &Global) -> JsValue;
}
/// Reader implementation for loading assets via HTTP in WASM.
pub struct HttpWasmAssetReader {
root_path: PathBuf,
@ -38,8 +53,22 @@ fn js_value_to_err<'a>(context: &'a str) -> impl FnOnce(JsValue) -> std::io::Err
impl HttpWasmAssetReader {
async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result<Box<Reader<'a>>, AssetReaderError> {
let window = web_sys::window().unwrap();
let resp_value = JsFuture::from(window.fetch_with_str(path.to_str().unwrap()))
// The JS global scope includes a self-reference via a specialising name, which can be used to determine the type of global context available.
let global: Global = js_sys::global().unchecked_into();
let promise = if !global.window().is_undefined() {
let window: web_sys::Window = global.unchecked_into();
window.fetch_with_str(path.to_str().unwrap())
} else if !global.worker().is_undefined() {
let worker: web_sys::WorkerGlobalScope = global.unchecked_into();
worker.fetch_with_str(path.to_str().unwrap())
} else {
let error = std::io::Error::new(
std::io::ErrorKind::Other,
"Unsupported JavaScript global context",
);
return Err(AssetReaderError::Io(error.into()));
};
let resp_value = JsFuture::from(promise)
.await
.map_err(js_value_to_err("fetch path"))?;
let resp = resp_value

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_audio"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides audio functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,22 +10,22 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
rodio = { version = "0.17", default-features = false }
[target.'cfg(target_os = "android")'.dependencies]
oboe = { version = "0.5", optional = true }
cpal = { version = "0.15", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
rodio = { version = "0.17", default-features = false, features = [
@ -45,7 +45,7 @@ symphonia-isomp4 = ["rodio/symphonia-isomp4"]
symphonia-vorbis = ["rodio/symphonia-vorbis"]
symphonia-wav = ["rodio/symphonia-wav"]
# Enable using a shared stdlib for cxx on Android.
android_shared_stdcxx = ["oboe/shared-stdcxx"]
android_shared_stdcxx = ["cpal/oboe-shared-stdcxx"]
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_core"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides core functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -11,18 +11,18 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2", features = [
"bevy_reflect",
] }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0", features = [
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2", features = [
"bevy_reflect",
] }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
bytemuck = "1.5"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_core_pipeline"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
@ -13,7 +13,7 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"]
[features]
dds = []
dds = ["bevy_render/dds"]
trace = []
webgl = []
webgpu = []
@ -21,17 +21,17 @@ tonemapping_luts = ["bevy_render/ktx2", "bevy_render/zstd"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
serde = { version = "1", features = ["derive"] }
bitflags = "2.3"

View File

@ -106,6 +106,8 @@ pub struct BloomSettings {
impl BloomSettings {
/// The default bloom preset.
///
/// This uses the [`EnergyConserving`](BloomCompositeMode::EnergyConserving) composite mode.
pub const NATURAL: Self = Self {
intensity: 0.15,
low_frequency_boost: 0.7,

View File

@ -93,6 +93,12 @@ impl ExtractComponent for Skybox {
skybox.clone(),
SkyboxUniforms {
brightness: skybox.brightness * exposure,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_8b: 0,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_12b: 0,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_16b: 0,
},
))
}
@ -102,6 +108,12 @@ impl ExtractComponent for Skybox {
#[derive(Component, ShaderType, Clone)]
pub struct SkyboxUniforms {
brightness: f32,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_8b: u32,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_12b: u32,
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_16b: u32,
}
#[derive(Resource)]

View File

@ -1,10 +1,19 @@
#import bevy_render::view::View
#import bevy_pbr::utils::coords_to_viewport_uv
struct SkyboxUniforms {
brightness: f32,
#ifdef SIXTEEN_BYTE_ALIGNMENT
_wasm_padding_8b: u32,
_wasm_padding_12b: u32,
_wasm_padding_16b: u32,
#endif
}
@group(0) @binding(0) var skybox: texture_cube<f32>;
@group(0) @binding(1) var skybox_sampler: sampler;
@group(0) @binding(2) var<uniform> view: View;
@group(0) @binding(3) var<uniform> brightness: f32;
@group(0) @binding(3) var<uniform> uniforms: SkyboxUniforms;
fn coords_to_ray_direction(position: vec2<f32>, viewport: vec4<f32>) -> vec3<f32> {
// Using world positions of the fragment and camera to calculate a ray direction
@ -63,5 +72,5 @@ fn skybox_fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let ray_direction = coords_to_ray_direction(in.position.xy, view.viewport);
// Cube maps are left-handed so we negate the z coordinate.
return textureSample(skybox, skybox_sampler, ray_direction * vec3(1.0, 1.0, -1.0)) * brightness;
return textureSample(skybox, skybox_sampler, ray_direction * vec3(1.0, 1.0, -1.0)) * uniforms.brightness;
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_derive"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides derive implementations for Bevy Engine"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.13.2" }
quote = "1.0"
syn = { version = "2.0", features = ["full"] }

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_diagnostic"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides diagnostic functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,12 +14,12 @@ dynamic_linking = []
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_time = { path = "../bevy_time", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_time = { path = "../bevy_time", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
const-fnv1a-hash = "1.1.0"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_dylib"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Force the Bevy Engine to be dynamically linked for faster linking"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
crate-type = ["dylib"]
[dependencies]
bevy_internal = { path = "../bevy_internal", version = "0.13.0", default-features = false }
bevy_internal = { path = "../bevy_internal", version = "0.13.2", default-features = false }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_dynamic_plugin"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides dynamic plugin loading capabilities for non-wasm platforms"
homepage = "https://bevyengine.org"
@ -10,7 +10,7 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
# other
libloading = { version = "0.8" }

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_ecs"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Bevy Engine's entity component system"
homepage = "https://bevyengine.org"
@ -16,11 +16,11 @@ bevy_debug_stepping = []
default = ["bevy_reflect", "bevy_debug_stepping"]
[dependencies]
bevy_ptr = { path = "../bevy_ptr", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", optional = true }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_ecs_macros = { path = "macros", version = "0.13.0" }
bevy_ptr = { path = "../bevy_ptr", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", optional = true }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_ecs_macros = { path = "macros", version = "0.13.2" }
async-channel = "2.1.0"
thread_local = "1.1.4"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_ecs_macros"
version = "0.13.0"
version = "0.13.2"
description = "Bevy ECS Macros"
edition = "2021"
license = "MIT OR Apache-2.0"
@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.2" }
syn = "2.0"
quote = "1.0"

View File

@ -21,8 +21,8 @@ pub(super) trait SystemExecutor: Send + Sync {
fn run(
&mut self,
schedule: &mut SystemSchedule,
skip_systems: Option<FixedBitSet>,
world: &mut World,
skip_systems: Option<&FixedBitSet>,
);
fn set_apply_final_deferred(&mut self, value: bool);
}

View File

@ -166,8 +166,8 @@ impl SystemExecutor for MultiThreadedExecutor {
fn run(
&mut self,
schedule: &mut SystemSchedule,
_skip_systems: Option<FixedBitSet>,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
) {
// reset counts
self.num_systems = schedule.systems.len();
@ -189,26 +189,18 @@ impl SystemExecutor for MultiThreadedExecutor {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(mut skipped_systems) = _skip_systems {
if let Some(skipped_systems) = _skip_systems {
debug_assert_eq!(skipped_systems.len(), self.completed_systems.len());
// mark skipped systems as completed
self.completed_systems |= &skipped_systems;
self.completed_systems |= skipped_systems;
self.num_completed_systems = self.completed_systems.count_ones(..);
// signal the dependencies for each of the skipped systems, as
// though they had run
for system_index in skipped_systems.ones() {
self.signal_dependents(system_index);
self.ready_systems.set(system_index, false);
}
// Finally, we need to clear all skipped systems from the ready
// list.
//
// We invert the skipped system mask to get the list of systems
// that should be run. Then we bitwise AND it with the ready list,
// resulting in a list of ready systems that aren't skipped.
skipped_systems.toggle_range(..);
self.ready_systems &= skipped_systems;
}
let thread_executor = world

View File

@ -4,7 +4,9 @@ use fixedbitset::FixedBitSet;
use std::panic::AssertUnwindSafe;
use crate::{
schedule::{BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
schedule::{
executor::is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
},
world::World,
};
@ -33,15 +35,15 @@ impl SystemExecutor for SimpleExecutor {
fn run(
&mut self,
schedule: &mut SystemSchedule,
_skip_systems: Option<FixedBitSet>,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= &skipped_systems;
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {
@ -86,6 +88,10 @@ impl SystemExecutor for SimpleExecutor {
}
let system = &mut schedule.systems[system_index];
if is_apply_deferred(system) {
continue;
}
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
system.run((), world);
}));
@ -125,3 +131,16 @@ fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut W
.map(|condition| condition.run((), world))
.fold(true, |acc, res| acc && res)
}
#[cfg(test)]
#[test]
fn skip_automatic_sync_points() {
// Schedules automatically insert appy_deferred systems, but these should
// not be executed as they only serve as markers and are not initialized
use crate::prelude::*;
let mut sched = Schedule::default();
sched.set_executor_kind(ExecutorKind::Simple);
sched.add_systems((|_: Commands| (), || ()).chain());
let mut world = World::new();
sched.run(&mut world);
}

View File

@ -41,15 +41,15 @@ impl SystemExecutor for SingleThreadedExecutor {
fn run(
&mut self,
schedule: &mut SystemSchedule,
_skip_systems: Option<FixedBitSet>,
world: &mut World,
_skip_systems: Option<&FixedBitSet>,
) {
// If stepping is enabled, make sure we skip those systems that should
// not be run.
#[cfg(feature = "bevy_debug_stepping")]
if let Some(skipped_systems) = _skip_systems {
// mark skipped systems as completed
self.completed_systems |= &skipped_systems;
self.completed_systems |= skipped_systems;
}
for system_index in 0..schedule.systems.len() {

View File

@ -333,15 +333,18 @@ impl Schedule {
.unwrap_or_else(|e| panic!("Error when initializing schedule {:?}: {e}", self.label));
#[cfg(not(feature = "bevy_debug_stepping"))]
let skip_systems = None;
self.executor.run(&mut self.executable, world, None);
#[cfg(feature = "bevy_debug_stepping")]
let skip_systems = match world.get_resource_mut::<Stepping>() {
None => None,
Some(mut stepping) => stepping.skipped_systems(self),
};
{
let skip_systems = match world.get_resource_mut::<Stepping>() {
None => None,
Some(mut stepping) => stepping.skipped_systems(self),
};
self.executor.run(&mut self.executable, skip_systems, world);
self.executor
.run(&mut self.executable, world, skip_systems.as_ref());
}
}
/// Initializes any newly-added systems and conditions, rebuilds the executable schedule,

View File

@ -9,7 +9,8 @@ use bevy_utils::intern::Interned;
pub use bevy_utils::label::DynEq;
use crate::system::{
ExclusiveSystemParamFunction, IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
ExclusiveFunctionSystem, ExclusiveSystemParamFunction, FunctionSystem,
IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
};
define_label!(
@ -167,26 +168,28 @@ impl<S: SystemSet> IntoSystemSet<()> for S {
// systems
impl<Marker, F> IntoSystemSet<(IsFunctionSystem, Marker)> for F
where
Marker: 'static,
F: SystemParamFunction<Marker>,
{
type Set = SystemTypeSet<Self>;
type Set = SystemTypeSet<FunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::new()
SystemTypeSet::<FunctionSystem<Marker, F>>::new()
}
}
// exclusive systems
impl<Marker, F> IntoSystemSet<(IsExclusiveFunctionSystem, Marker)> for F
where
Marker: 'static,
F: ExclusiveSystemParamFunction<Marker>,
{
type Set = SystemTypeSet<Self>;
type Set = SystemTypeSet<ExclusiveFunctionSystem<Marker, F>>;
#[inline]
fn into_system_set(self) -> Self::Set {
SystemTypeSet::new()
SystemTypeSet::<ExclusiveFunctionSystem<Marker, F>>::new()
}
}

View File

@ -143,7 +143,7 @@ where
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
let set = crate::schedule::SystemTypeSet::<F>::new();
let set = crate::schedule::SystemTypeSet::<Self>::new();
vec![set.intern()]
}

View File

@ -536,7 +536,7 @@ where
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
let set = crate::schedule::SystemTypeSet::<F>::new();
let set = crate::schedule::SystemTypeSet::<Self>::new();
vec![set.intern()]
}

View File

@ -38,9 +38,11 @@ impl<I, O> RemovedSystem<I, O> {
///
/// These are opaque identifiers, keyed to a specific [`World`],
/// and are created via [`World::register_system`].
#[derive(Eq)]
pub struct SystemId<I = (), O = ()>(Entity, std::marker::PhantomData<fn(I) -> O>);
// A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters.
impl<I, O> Eq for SystemId<I, O> {}
// A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters.
impl<I, O> Copy for SystemId<I, O> {}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_encase_derive"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Bevy derive macro for encase"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.13.2" }
encase_derive_impl = "0.7"
[lints]

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_gilrs"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Gamepad system made using Gilrs for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,12 +10,12 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_input = { path = "../bevy_input", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_time = { path = "../bevy_time", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_input = { path = "../bevy_input", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_time = { path = "../bevy_time", version = "0.13.2" }
# other
gilrs = "0.10.1"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_gizmos"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides gizmos for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,20 +14,20 @@ webgpu = []
[dependencies]
# Bevy
bevy_pbr = { path = "../bevy_pbr", version = "0.13.0", optional = true }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.0", optional = true }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_gizmos_macros = { path = "macros", version = "0.13.0" }
bevy_pbr = { path = "../bevy_pbr", version = "0.13.2", optional = true }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.2", optional = true }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_gizmos_macros = { path = "macros", version = "0.13.2" }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_gizmos_macros"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Derive implementations for bevy_gizmos"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.2" }
syn = "2.0"
proc-macro2 = "1.0"

View File

@ -3,8 +3,8 @@
use crate as bevy_gizmos;
pub use bevy_gizmos_macros::GizmoConfigGroup;
use bevy_ecs::{component::Component, system::Resource};
use bevy_reflect::{Reflect, TypePath};
use bevy_ecs::{component::Component, reflect::ReflectResource, system::Resource};
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
use bevy_render::view::RenderLayers;
use bevy_utils::TypeIdMap;
use core::panic;
@ -27,9 +27,11 @@ pub struct DefaultGizmoConfigGroup;
/// A [`Resource`] storing [`GizmoConfig`] and [`GizmoConfigGroup`] structs
///
/// Use `app.init_gizmo_group::<T>()` to register a custom config group.
#[derive(Resource, Default)]
#[derive(Reflect, Resource, Default)]
#[reflect(Resource, Default)]
pub struct GizmoConfigStore {
// INVARIANT: must map TypeId::of::<T>() to correct type T
#[reflect(ignore)]
store: TypeIdMap<(GizmoConfig, Box<dyn Reflect>)>,
}

View File

@ -319,7 +319,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
SphereBuilder {
gizmos: self,
position,
rotation,
rotation: rotation.normalize(),
radius,
color,
circle_segments: DEFAULT_CIRCLE_SEGMENTS,

View File

@ -98,6 +98,7 @@ impl Plugin for GizmoPlugin {
load_internal_asset!(app, LINE_SHADER_HANDLE, "lines.wgsl", Shader::from_wgsl);
app.register_type::<GizmoConfig>()
.register_type::<GizmoConfigStore>()
.add_plugins(UniformComponentPlugin::<LineGizmoUniform>::default())
.init_asset::<LineGizmo>()
.add_plugins(RenderAssetPlugin::<LineGizmo>::default())

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_gltf"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Bevy Engine GLTF loading"
homepage = "https://bevyengine.org"
@ -14,26 +14,26 @@ pbr_transmission_textures = []
[dependencies]
# bevy
bevy_animation = { path = "../bevy_animation", version = "0.13.0", optional = true }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_pbr = { path = "../bevy_pbr", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_animation = { path = "../bevy_animation", version = "0.13.2", optional = true }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_pbr = { path = "../bevy_pbr", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_scene = { path = "../bevy_scene", version = "0.13.0", features = [
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_scene = { path = "../bevy_scene", version = "0.13.2", features = [
"bevy_render",
] }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
gltf = { version = "1.4.0", default-features = false, features = [

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_hierarchy"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides hierarchy functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -16,14 +16,14 @@ reflect = ["bevy_ecs/bevy_reflect", "bevy_reflect"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0", optional = true }
bevy_core = { path = "../bevy_core", version = "0.13.0", optional = true }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0", default-features = false }
bevy_log = { path = "../bevy_log", version = "0.13.0", optional = true }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2", optional = true }
bevy_core = { path = "../bevy_core", version = "0.13.2", optional = true }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2", default-features = false }
bevy_log = { path = "../bevy_log", version = "0.13.2", optional = true }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
], optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_input"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides input functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,11 +14,11 @@ serialize = ["serde"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"glam",
"smol_str",
] }

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_internal"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "An internal Bevy crate used to facilitate optional dynamic linking via the 'dynamic_linking' feature"
homepage = "https://bevyengine.org"
@ -162,41 +162,41 @@ bevy_debug_stepping = [
[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_input = { path = "../bevy_input", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_ptr = { path = "../bevy_ptr", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_a11y = { path = "../bevy_a11y", version = "0.13.2" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_input = { path = "../bevy_input", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_ptr = { path = "../bevy_ptr", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_time = { path = "../bevy_time", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_time = { path = "../bevy_time", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
# bevy (optional)
bevy_animation = { path = "../bevy_animation", optional = true, version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", optional = true, version = "0.13.0" }
bevy_audio = { path = "../bevy_audio", optional = true, version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.13.0" }
bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.13.0" }
bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.13.0" }
bevy_render = { path = "../bevy_render", optional = true, version = "0.13.0" }
bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.13.0" }
bevy_scene = { path = "../bevy_scene", optional = true, version = "0.13.0" }
bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.13.0" }
bevy_text = { path = "../bevy_text", optional = true, version = "0.13.0" }
bevy_ui = { path = "../bevy_ui", optional = true, version = "0.13.0" }
bevy_winit = { path = "../bevy_winit", optional = true, version = "0.13.0" }
bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.13.0" }
bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.13.0", default-features = false }
bevy_animation = { path = "../bevy_animation", optional = true, version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", optional = true, version = "0.13.2" }
bevy_audio = { path = "../bevy_audio", optional = true, version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.13.2" }
bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.13.2" }
bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.13.2" }
bevy_render = { path = "../bevy_render", optional = true, version = "0.13.2" }
bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.13.2" }
bevy_scene = { path = "../bevy_scene", optional = true, version = "0.13.2" }
bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.13.2" }
bevy_text = { path = "../bevy_text", optional = true, version = "0.13.2" }
bevy_ui = { path = "../bevy_ui", optional = true, version = "0.13.2" }
bevy_winit = { path = "../bevy_winit", optional = true, version = "0.13.2" }
bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.13.2" }
bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.13.2", default-features = false }
[lints]
workspace = true

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_log"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides logging for Bevy Engine"
homepage = "https://bevyengine.org"
@ -13,9 +13,9 @@ trace = ["tracing-error"]
trace_tracy_memory = ["dep:tracy-client"]
[dependencies]
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
tracing-subscriber = { version = "0.3.1", features = [
"registry",

View File

@ -3,7 +3,10 @@ use bevy_utils::tracing::{
span::{Attributes, Record},
Event, Id, Level, Subscriber,
};
use std::fmt::{Debug, Write};
use std::{
ffi::CString,
fmt::{Debug, Write},
};
use tracing_subscriber::{field::Visit, layer::Context, registry::LookupSpan, Layer};
#[derive(Default)]
@ -37,16 +40,6 @@ impl Visit for StringRecorder {
}
}
impl core::fmt::Display for StringRecorder {
fn fmt(&self, mut f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if !self.0.is_empty() {
write!(&mut f, " {}", self.0)
} else {
Ok(())
}
}
}
impl core::default::Default for StringRecorder {
fn default() -> Self {
StringRecorder::new()
@ -74,24 +67,33 @@ impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for AndroidLayer {
}
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
fn sanitize(string: &str) -> CString {
let mut bytes: Vec<u8> = string
.as_bytes()
.into_iter()
.copied()
.filter(|byte| *byte != 0)
.collect();
CString::new(bytes).unwrap()
}
let mut recorder = StringRecorder::new();
event.record(&mut recorder);
let meta = event.metadata();
let level = meta.level();
let priority = match *level {
let priority = match *meta.level() {
Level::TRACE => android_log_sys::LogPriority::VERBOSE,
Level::DEBUG => android_log_sys::LogPriority::DEBUG,
Level::INFO => android_log_sys::LogPriority::INFO,
Level::WARN => android_log_sys::LogPriority::WARN,
Level::ERROR => android_log_sys::LogPriority::ERROR,
};
let message = format!("{}\0", recorder);
let tag = format!("{}\0", meta.name());
// SAFETY: Called only on Android platforms. priority is guaranteed to be in range of c_int.
// The provided tag and message are null terminated properly.
unsafe {
android_log_sys::__android_log_write(
priority as android_log_sys::c_int,
tag.as_ptr() as *const android_log_sys::c_char,
message.as_ptr() as *const android_log_sys::c_char,
sanitize(meta.name()).as_ptr(),
sanitize(&recorder.0).as_ptr(),
);
}
}

View File

@ -217,12 +217,12 @@ impl Plugin for LogPlugin {
bevy_utils::tracing::subscriber::set_global_default(finished_subscriber).is_err();
match (logger_already_set, subscriber_already_set) {
(true, true) => warn!(
(true, true) => error!(
"Could not set global logger and tracing subscriber as they are already set. Consider disabling LogPlugin."
),
(true, _) => warn!("Could not set global logger as it is already set. Consider disabling LogPlugin."),
(_, true) => warn!("Could not set global tracing subscriber as it is already set. Consider disabling LogPlugin."),
_ => (),
(true, false) => error!("Could not set global logger as it is already set. Consider disabling LogPlugin."),
(false, true) => error!("Could not set global tracing subscriber as it is already set. Consider disabling LogPlugin."),
(false, false) => (),
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_macro_utils"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "A collection of utils for Bevy Engine"
homepage = "https://bevyengine.org"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_math"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides math functionality for Bevy Engine"
homepage = "https://bevyengine.org"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_mikktspace"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
authors = [
"Benjamin Wasty <benny.wasty@gmail.com>",

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_pbr"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Adds PBR rendering to Bevy Engine"
homepage = "https://bevyengine.org"
@ -15,19 +15,19 @@ pbr_transmission_textures = []
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
# other
bitflags = "2.3"

View File

@ -590,7 +590,7 @@ fn calculate_cascade(
// It is critical for `world_to_cascade` to be stable. So rather than forming `cascade_to_world`
// and inverting it, which risks instability due to numerical precision, we directly form
// `world_to_cascde` as the reference material suggests.
// `world_to_cascade` as the reference material suggests.
let light_to_world_transpose = light_to_world.transpose();
let world_to_cascade = Mat4::from_cols(
light_to_world_transpose.x_axis,

View File

@ -793,7 +793,19 @@ pub struct PreparedMaterial<T: Material> {
}
#[derive(Component, Clone, Copy, Default, PartialEq, Eq, Deref, DerefMut)]
pub struct MaterialBindGroupId(Option<BindGroupId>);
pub struct MaterialBindGroupId(pub Option<BindGroupId>);
impl MaterialBindGroupId {
pub fn new(id: BindGroupId) -> Self {
Self(Some(id))
}
}
impl From<BindGroup> for MaterialBindGroupId {
fn from(value: BindGroup) -> Self {
Self::new(value.id())
}
}
impl<T: Material> PreparedMaterial<T> {
pub fn get_bind_group_id(&self) -> MaterialBindGroupId {

View File

@ -6,7 +6,7 @@ use bevy_render::{
camera::Camera,
color::Color,
mesh::Mesh,
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
primitives::{CascadesFrusta, CubemapFrusta, Frustum, HalfSpace},
render_asset::RenderAssets,
render_graph::{Node, NodeRunError, RenderGraphContext},
render_phase::*,
@ -29,30 +29,30 @@ use crate::*;
#[derive(Component)]
pub struct ExtractedPointLight {
color: Color,
pub color: Color,
/// luminous intensity in lumens per steradian
intensity: f32,
range: f32,
radius: f32,
transform: GlobalTransform,
shadows_enabled: bool,
shadow_depth_bias: f32,
shadow_normal_bias: f32,
spot_light_angles: Option<(f32, f32)>,
pub intensity: f32,
pub range: f32,
pub radius: f32,
pub transform: GlobalTransform,
pub shadows_enabled: bool,
pub shadow_depth_bias: f32,
pub shadow_normal_bias: f32,
pub spot_light_angles: Option<(f32, f32)>,
}
#[derive(Component, Debug)]
pub struct ExtractedDirectionalLight {
color: Color,
illuminance: f32,
transform: GlobalTransform,
shadows_enabled: bool,
shadow_depth_bias: f32,
shadow_normal_bias: f32,
cascade_shadow_config: CascadeShadowConfig,
cascades: EntityHashMap<Vec<Cascade>>,
frusta: EntityHashMap<Vec<Frustum>>,
render_layers: RenderLayers,
pub color: Color,
pub illuminance: f32,
pub transform: GlobalTransform,
pub shadows_enabled: bool,
pub shadow_depth_bias: f32,
pub shadow_normal_bias: f32,
pub cascade_shadow_config: CascadeShadowConfig,
pub cascades: EntityHashMap<Vec<Cascade>>,
pub frusta: EntityHashMap<Vec<Frustum>>,
pub render_layers: RenderLayers,
}
#[derive(Copy, Clone, ShaderType, Default, Debug)]
@ -1145,7 +1145,7 @@ pub fn prepare_lights(
.unwrap()
.iter()
.take(MAX_CASCADES_PER_LIGHT);
for (cascade_index, ((cascade, frusta), bound)) in cascades
for (cascade_index, ((cascade, frustum), bound)) in cascades
.zip(frusta)
.zip(&light.cascade_shadow_config.bounds)
.enumerate()
@ -1172,6 +1172,11 @@ pub fn prepare_lights(
});
directional_depth_texture_array_index += 1;
let mut frustum = *frustum;
// Push the near clip plane out to infinity for directional lights
frustum.half_spaces[4] =
HalfSpace::new(frustum.half_spaces[4].normal().extend(f32::INFINITY));
let view_light_entity = commands
.spawn((
ShadowView {
@ -1192,7 +1197,7 @@ pub fn prepare_lights(
hdr: false,
color_grading: Default::default(),
},
*frusta,
frustum,
RenderPhase::<Shadow>::default(),
LightEntity::Directional {
light_entity,
@ -1210,16 +1215,20 @@ pub fn prepare_lights(
.create_view(&TextureViewDescriptor {
label: Some("point_light_shadow_map_array_texture_view"),
format: None,
#[cfg(any(
not(feature = "webgl"),
not(target_arch = "wasm32"),
feature = "webgpu"
// NOTE: iOS Simulator is missing CubeArray support so we use Cube instead.
// See https://github.com/bevyengine/bevy/pull/12052 - remove if support is added.
#[cfg(all(
not(ios_simulator),
any(
not(feature = "webgl"),
not(target_arch = "wasm32"),
feature = "webgpu"
)
))]
dimension: Some(TextureViewDimension::CubeArray),
#[cfg(all(
feature = "webgl",
target_arch = "wasm32",
not(feature = "webgpu")
#[cfg(any(
ios_simulator,
all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))
))]
dimension: Some(TextureViewDimension::Cube),
aspect: TextureAspect::DepthOnly,

View File

@ -191,13 +191,19 @@ fn layout_entries(
// Point Shadow Texture Cube Array
(
2,
#[cfg(any(
not(feature = "webgl"),
not(target_arch = "wasm32"),
feature = "webgpu"
#[cfg(all(
not(ios_simulator),
any(
not(feature = "webgl"),
not(target_arch = "wasm32"),
feature = "webgpu"
)
))]
texture_cube_array(TextureSampleType::Depth),
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
#[cfg(any(
ios_simulator,
all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu"))
))]
texture_cube(TextureSampleType::Depth),
),
// Point Shadow Texture Array Sampler
@ -250,7 +256,10 @@ fn layout_entries(
),
),
// Globals
(9, uniform_buffer::<GlobalsUniform>(false)),
(
9,
uniform_buffer::<GlobalsUniform>(false).visibility(ShaderStages::VERTEX_FRAGMENT),
),
// Fog
(10, uniform_buffer::<GpuFog>(true)),
// Light probes

View File

@ -8,7 +8,7 @@
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<uniform> lights: types::Lights;
#ifdef NO_ARRAY_TEXTURES_SUPPORT
#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT
@group(0) @binding(2) var point_shadow_textures: texture_depth_cube;
#else
@group(0) @binding(2) var point_shadow_textures: texture_depth_cube_array;

View File

@ -109,6 +109,6 @@ pub fn no_automatic_morph_batching(
query: Query<Entity, (With<MeshMorphWeights>, Without<NoAutomaticBatching>)>,
) {
for entity in &query {
commands.entity(entity).insert(NoAutomaticBatching);
commands.entity(entity).try_insert(NoAutomaticBatching);
}
}

View File

@ -44,7 +44,7 @@ fn fetch_point_shadow(light_id: u32, frag_position: vec4<f32>, surface_normal: v
// a quad (2x2 fragments) being processed not being sampled, and this messing with
// mip-mapping functionality. The shadow maps have no mipmaps so Level just samples
// from LOD 0.
#ifdef NO_ARRAY_TEXTURES_SUPPORT
#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT
return textureSampleCompare(view_bindings::point_shadow_textures, view_bindings::point_shadow_textures_sampler, frag_ls * flip_z, depth);
#else
return textureSampleCompareLevel(view_bindings::point_shadow_textures, view_bindings::point_shadow_textures_sampler, frag_ls * flip_z, i32(light_id), depth);

View File

@ -146,6 +146,6 @@ pub fn no_automatic_skin_batching(
query: Query<Entity, (With<SkinnedMesh>, Without<NoAutomaticBatching>)>,
) {
for entity in &query {
commands.entity(entity).insert(NoAutomaticBatching);
commands.entity(entity).try_insert(NoAutomaticBatching);
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_ptr"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Utilities for working with untyped pointers in a more safe way"
homepage = "https://bevyengine.org"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_reflect"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Dynamically interact with rust types"
homepage = "https://bevyengine.org"
@ -21,12 +21,12 @@ documentation = ["bevy_reflect_derive/documentation"]
[dependencies]
# bevy
bevy_math = { path = "../bevy_math", version = "0.13.0", features = [
bevy_math = { path = "../bevy_math", version = "0.13.2", features = [
"serialize",
], optional = true }
bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_ptr = { path = "../bevy_ptr", version = "0.13.0" }
bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_ptr = { path = "../bevy_ptr", version = "0.13.2" }
# other
erased-serde = "0.4"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_reflect_derive"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Derive implementations for bevy_reflect"
homepage = "https://bevyengine.org"
@ -17,7 +17,7 @@ default = []
documentation = []
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.2" }
syn = { version = "2.0", features = ["full"] }
proc-macro2 = "1.0"

View File

@ -805,8 +805,12 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> {
)?
.into(),
};
dynamic_enum.set_variant(variant_info.name(), value);
let variant_name = variant_info.name();
let variant_index = self
.enum_info
.index_of(variant_name)
.expect("variant should exist");
dynamic_enum.set_variant_with_index(variant_index, variant_name, value);
Ok(dynamic_enum)
}
}
@ -1110,7 +1114,7 @@ mod tests {
use bevy_utils::HashMap;
use crate as bevy_reflect;
use crate::serde::{TypedReflectDeserializer, UntypedReflectDeserializer};
use crate::serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer};
use crate::{DynamicEnum, FromReflect, Reflect, ReflectDeserialize, TypeRegistry};
#[derive(Reflect, Debug, PartialEq)]
@ -1168,7 +1172,7 @@ mod tests {
#[reflect(Deserialize)]
struct CustomDeserialize {
value: usize,
#[serde(rename = "renamed")]
#[serde(alias = "renamed")]
inner_struct: SomeDeserializableStruct,
}
@ -1218,12 +1222,11 @@ mod tests {
registry
}
#[test]
fn should_deserialize() {
fn get_my_struct() -> MyStruct {
let mut map = HashMap::new();
map.insert(64, 32);
let expected = MyStruct {
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
@ -1250,7 +1253,13 @@ mod tests {
value: 100,
inner_struct: SomeDeserializableStruct { foo: 101 },
},
};
}
}
#[test]
fn should_deserialize() {
let expected = get_my_struct();
let registry = get_registry();
let input = r#"{
"bevy_reflect::serde::de::tests::MyStruct": (
@ -1295,7 +1304,6 @@ mod tests {
),
}"#;
let registry = get_registry();
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
let dynamic_output = reflect_deserializer
@ -1477,40 +1485,28 @@ mod tests {
assert!(expected.reflect_partial_eq(output.as_ref()).unwrap());
}
// Regression test for https://github.com/bevyengine/bevy/issues/12462
#[test]
fn should_reserialize() {
let registry = get_registry();
let input1 = get_my_struct();
let serializer1 = ReflectSerializer::new(&input1, &registry);
let serialized1 = ron::ser::to_string(&serializer1).unwrap();
let mut deserializer = ron::de::Deserializer::from_str(&serialized1).unwrap();
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
let input2 = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let serializer2 = ReflectSerializer::new(&*input2, &registry);
let serialized2 = ron::ser::to_string(&serializer2).unwrap();
assert_eq!(serialized1, serialized2);
}
#[test]
fn should_deserialize_non_self_describing_binary() {
let mut map = HashMap::new();
map.insert(64, 32);
let expected = MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 0 },
ignored_tuple_struct: SomeIgnoredTupleStruct(0),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::default(),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(0.0, 0.0),
custom_deserialize: CustomDeserialize {
value: 100,
inner_struct: SomeDeserializableStruct { foo: 101 },
},
};
let expected = get_my_struct();
let registry = get_registry();
let input = vec![
@ -1542,38 +1538,7 @@ mod tests {
#[test]
fn should_deserialize_self_describing_binary() {
let mut map = HashMap::new();
map.insert(64, 32);
let expected = MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 0 },
ignored_tuple_struct: SomeIgnoredTupleStruct(0),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::default(),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(0.0, 0.0),
custom_deserialize: CustomDeserialize {
value: 100,
inner_struct: SomeDeserializableStruct { foo: 101 },
},
};
let expected = get_my_struct();
let registry = get_registry();
let input = vec![

View File

@ -32,12 +32,19 @@ fn get_serializable<'a, E: Error>(
reflect_value: &'a dyn Reflect,
type_registry: &TypeRegistry,
) -> Result<Serializable<'a>, E> {
let info = reflect_value.get_represented_type_info().ok_or_else(|| {
Error::custom(format_args!(
"Type '{}' does not represent any type",
reflect_value.reflect_type_path(),
))
})?;
let reflect_serialize = type_registry
.get_type_data::<ReflectSerialize>(reflect_value.type_id())
.get_type_data::<ReflectSerialize>(info.type_id())
.ok_or_else(|| {
Error::custom(format_args!(
"Type '{}' did not register ReflectSerialize",
reflect_value.reflect_type_path()
info.type_path(),
))
})?;
Ok(reflect_serialize.get_serializable(reflect_value))
@ -567,12 +574,10 @@ mod tests {
registry
}
#[test]
fn should_serialize() {
fn get_my_struct() -> MyStruct {
let mut map = HashMap::new();
map.insert(64, 32);
let input = MyStruct {
MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
@ -599,9 +604,14 @@ mod tests {
value: 100,
inner_struct: SomeSerializableStruct { foo: 101 },
},
};
}
}
#[test]
fn should_serialize() {
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
let config = PrettyConfig::default()
@ -769,38 +779,7 @@ mod tests {
#[test]
fn should_serialize_non_self_describing_binary() {
let mut map = HashMap::new();
map.insert(64, 32);
let input = MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 123 },
ignored_tuple_struct: SomeIgnoredTupleStruct(123),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::from("Struct Variant"),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),
custom_serialize: CustomSerialize {
value: 100,
inner_struct: SomeSerializableStruct { foo: 101 },
},
};
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);
@ -827,38 +806,7 @@ mod tests {
#[test]
fn should_serialize_self_describing_binary() {
let mut map = HashMap::new();
map.insert(64, 32);
let input = MyStruct {
primitive_value: 123,
option_value: Some(String::from("Hello world!")),
option_value_complex: Some(SomeStruct { foo: 123 }),
tuple_value: (PI, 1337),
list_value: vec![-2, -1, 0, 1, 2],
array_value: [-2, -1, 0, 1, 2],
map_value: map,
struct_value: SomeStruct { foo: 999999999 },
tuple_struct_value: SomeTupleStruct(String::from("Tuple Struct")),
unit_struct: SomeUnitStruct,
unit_enum: SomeEnum::Unit,
newtype_enum: SomeEnum::NewType(123),
tuple_enum: SomeEnum::Tuple(1.23, 3.21),
struct_enum: SomeEnum::Struct {
foo: String::from("Struct variant value"),
},
ignored_struct: SomeIgnoredStruct { ignored: 123 },
ignored_tuple_struct: SomeIgnoredTupleStruct(123),
ignored_struct_variant: SomeIgnoredEnum::Struct {
foo: String::from("Struct Variant"),
},
ignored_tuple_variant: SomeIgnoredEnum::Tuple(1.23, 3.45),
custom_serialize: CustomSerialize {
value: 100,
inner_struct: SomeSerializableStruct { foo: 101 },
},
};
let input = get_my_struct();
let registry = get_registry();
let serializer = ReflectSerializer::new(&input, &registry);

View File

@ -1,4 +1,4 @@
use crate::{serde::Serializable, Reflect, TypeInfo, TypePath, Typed};
use crate::{serde::Serializable, FromReflect, Reflect, TypeInfo, TypePath, Typed};
use bevy_ptr::{Ptr, PtrMut};
use bevy_utils::{HashMap, HashSet, TypeIdMap};
use downcast_rs::{impl_downcast, Downcast};
@ -435,14 +435,20 @@ pub struct ReflectSerialize {
get_serializable: for<'a> fn(value: &'a dyn Reflect) -> Serializable,
}
impl<T: Reflect + erased_serde::Serialize> FromType<T> for ReflectSerialize {
impl<T: TypePath + FromReflect + erased_serde::Serialize> FromType<T> for ReflectSerialize {
fn from_type() -> Self {
ReflectSerialize {
get_serializable: |value| {
let value = value.downcast_ref::<T>().unwrap_or_else(|| {
panic!("ReflectSerialize::get_serialize called with type `{}`, even though it was created for `{}`", value.reflect_type_path(), std::any::type_name::<T>())
});
Serializable::Borrowed(value)
value
.downcast_ref::<T>()
.map(|value| Serializable::Borrowed(value))
.or_else(|| T::from_reflect(value).map(|value| Serializable::Owned(Box::new(value))))
.unwrap_or_else(|| {
panic!(
"FromReflect::from_reflect failed when called on type `{}` with this value: {value:?}",
T::type_path(),
);
})
},
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_render"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides rendering functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -37,25 +37,25 @@ webgpu = ["wgpu/webgpu"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core = { path = "../bevy_core", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_encase_derive = { path = "../bevy_encase_derive", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render_macros = { path = "macros", version = "0.13.0" }
bevy_time = { path = "../bevy_time", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_render_macros = { path = "macros", version = "0.13.2" }
bevy_time = { path = "../bevy_time", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
# rendering
image = { version = "0.24", default-features = false }
@ -64,7 +64,7 @@ image = { version = "0.24", default-features = false }
codespan-reporting = "0.11.0"
# `fragile-send-sync-non-atomic-wasm` feature means we can't use WASM threads for rendering
# It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm
wgpu = { version = "0.19.1", default-features = false, features = [
wgpu = { version = "0.19.3", default-features = false, features = [
"wgsl",
"dx12",
"metal",
@ -74,7 +74,7 @@ wgpu = { version = "0.19.1", default-features = false, features = [
] }
naga = { version = "0.19", features = ["wgsl-in"] }
serde = { version = "1", features = ["derive"] }
bitflags = "2.3"
bitflags = { version = "2.3", features = ["serde"] }
bytemuck = { version = "1.5", features = ["derive"] }
downcast-rs = "1.2.0"
thread_local = "1.1"
@ -105,9 +105,7 @@ naga_oil = { version = "0.13", default-features = false, features = [
[target.'cfg(target_arch = "wasm32")'.dependencies]
naga_oil = "0.13"
js-sys = "0.3"
# web-sys doesn't follow semver for the WebGPU APIs as they are unstable
# Make sure that WebGPU builds work when changing this!
web-sys = { version = "=0.3.67", features = [
web-sys = { version = "0.3.67", features = [
'Blob',
'Document',
'Element',

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_render_macros"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Derive implementations for bevy_render"
homepage = "https://bevyengine.org"
@ -12,7 +12,7 @@ keywords = ["bevy"]
proc-macro = true
[dependencies]
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.0" }
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.13.2" }
syn = "2.0"
proc-macro2 = "1.0"

View File

@ -360,6 +360,7 @@ impl Plugin for RenderPlugin {
.insert_resource(instance)
.insert_resource(PipelineCache::new(
device.clone(),
render_adapter.clone(),
self.synchronous_pipeline_compilation,
))
.insert_resource(device)

View File

@ -66,6 +66,13 @@ bitflags::bitflags! {
///
/// If you have an asset that doesn't actually need to end up in the render world, like an Image
/// that will be decoded into another Image asset, use `MAIN_WORLD` only.
///
/// ## Platform-specific
///
/// On Wasm, it is not possible for now to free reserved memory. To control memory usage, load assets
/// in sequence and unload one before loading the next. See this
/// [discussion about memory management](https://github.com/WebAssembly/design/issues/1397) for more
/// details.
#[repr(transparent)]
#[derive(Serialize, TypePath, Deserialize, Hash, Clone, Copy, PartialEq, Eq, Debug)]
pub struct RenderAssetUsages: u8 {

View File

@ -1,3 +1,4 @@
use crate::renderer::RenderAdapter;
use crate::{render_resource::*, renderer::RenderDevice, Extract};
use bevy_asset::{AssetEvent, AssetId, Assets};
use bevy_ecs::system::{Res, ResMut};
@ -21,7 +22,7 @@ use thiserror::Error;
#[cfg(feature = "shader_format_spirv")]
use wgpu::util::make_spirv;
use wgpu::{
Features, PipelineLayoutDescriptor, PushConstantRange, ShaderModuleDescriptor,
DownlevelFlags, Features, PipelineLayoutDescriptor, PushConstantRange, ShaderModuleDescriptor,
VertexBufferLayout as RawVertexBufferLayout,
};
@ -167,7 +168,7 @@ impl ShaderDefVal {
}
impl ShaderCache {
fn new(render_device: &RenderDevice) -> Self {
fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
const CAPABILITIES: &[(Features, Capabilities)] = &[
(Features::PUSH_CONSTANTS, Capabilities::PUSH_CONSTANT),
(Features::SHADER_F64, Capabilities::FLOAT64),
@ -196,9 +197,13 @@ impl ShaderCache {
}
}
// TODO: Check if this is supported, though I'm not sure if bevy works without this feature?
// We can't compile for native at least without it.
capabilities |= Capabilities::CUBE_ARRAY_TEXTURES;
if render_adapter
.get_downlevel_capabilities()
.flags
.contains(DownlevelFlags::CUBE_ARRAY_TEXTURES)
{
capabilities |= Capabilities::CUBE_ARRAY_TEXTURES;
}
#[cfg(debug_assertions)]
let composer = naga_oil::compose::Composer::default();
@ -279,9 +284,14 @@ impl ShaderCache {
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
{
shader_defs.push("NO_ARRAY_TEXTURES_SUPPORT".into());
shader_defs.push("NO_CUBE_ARRAY_TEXTURES_SUPPORT".into());
shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into());
}
if cfg!(ios_simulator) {
shader_defs.push("NO_CUBE_ARRAY_TEXTURES_SUPPORT".into());
}
shader_defs.push(ShaderDefVal::UInt(
String::from("AVAILABLE_STORAGE_BUFFER_BINDINGS"),
render_device.limits().max_storage_buffers_per_shader_stage,
@ -491,9 +501,13 @@ impl PipelineCache {
}
/// Create a new pipeline cache associated with the given render device.
pub fn new(device: RenderDevice, synchronous_pipeline_compilation: bool) -> Self {
pub fn new(
device: RenderDevice,
render_adapter: RenderAdapter,
synchronous_pipeline_compilation: bool,
) -> Self {
Self {
shader_cache: Arc::new(Mutex::new(ShaderCache::new(&device))),
shader_cache: Arc::new(Mutex::new(ShaderCache::new(&device, &render_adapter))),
device,
layout_cache: default(),
waiting_pipelines: default(),
@ -881,7 +895,9 @@ impl PipelineCache {
CachedPipelineState::Err(err) => match err {
// Retry
PipelineCacheError::ShaderNotLoaded(_)
| PipelineCacheError::ShaderImportNotYetAvailable => {}
| PipelineCacheError::ShaderImportNotYetAvailable => {
cached_pipeline.state = CachedPipelineState::Queued;
}
// Shader could not be processed ... retrying won't help
PipelineCacheError::ProcessShaderError(err) => {

View File

@ -165,6 +165,15 @@ pub async fn initialize_renderer(
// integrated GPUs.
features -= wgpu::Features::MAPPABLE_PRIMARY_BUFFERS;
}
// RAY_QUERY and RAY_TRACING_ACCELERATION STRUCTURE will sometimes cause DeviceLost failures on platforms
// that report them as supported:
// <https://github.com/gfx-rs/wgpu/issues/5488>
// WGPU also currently doesn't actually support these features yet, so we should disable
// them until they are safe to enable.
features -= wgpu::Features::RAY_QUERY;
features -= wgpu::Features::RAY_TRACING_ACCELERATION_STRUCTURE;
limits = adapter.limits();
}

View File

@ -118,6 +118,8 @@ impl Plugin for ImagePlugin {
feature = "bmp",
feature = "basis-universal",
feature = "ktx2",
feature = "webp",
feature = "pnm"
))]
app.preregister_asset_loader::<ImageLoader>(IMG_FILE_EXTENSIONS);
}
@ -131,6 +133,8 @@ impl Plugin for ImagePlugin {
feature = "bmp",
feature = "basis-universal",
feature = "ktx2",
feature = "webp",
feature = "pnm"
))]
{
app.init_asset_loader::<ImageLoader>();

View File

@ -498,7 +498,7 @@ pub fn prepare_view_targets(
_ => Some(clear_color_global.0),
};
let (a, b, sampled) = textures
let (a, b, sampled, main_texture) = textures
.entry((camera.target.clone(), view.hdr))
.or_insert_with(|| {
let descriptor = TextureDescriptor {
@ -547,13 +547,14 @@ pub fn prepare_view_targets(
} else {
None
};
(a, b, sampled)
let main_texture = Arc::new(AtomicUsize::new(0));
(a, b, sampled, main_texture)
});
let main_textures = MainTargetTextures {
a: ColorAttachment::new(a.clone(), sampled.clone(), clear_color),
b: ColorAttachment::new(b.clone(), sampled.clone(), clear_color),
main_texture: Arc::new(AtomicUsize::new(0)),
main_texture: main_texture.clone(),
};
commands.entity(entity).insert(ViewTarget {

View File

@ -8,6 +8,8 @@ use crate::{
};
use bevy_app::{App, Plugin};
use bevy_ecs::{entity::EntityHashMap, prelude::*};
#[cfg(target_os = "linux")]
use bevy_utils::warn_once;
use bevy_utils::{default, tracing::debug, HashSet};
use bevy_window::{
CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed,
@ -17,7 +19,8 @@ use std::{
sync::PoisonError,
};
use wgpu::{
BufferUsages, SurfaceTargetUnsafe, TextureFormat, TextureUsages, TextureViewDescriptor,
BufferUsages, SurfaceConfiguration, SurfaceTargetUnsafe, TextureFormat, TextureUsages,
TextureViewDescriptor,
};
pub mod screenshot;
@ -42,7 +45,7 @@ impl Plugin for WindowRenderPlugin {
.add_systems(
Render,
create_surfaces
.run_if(need_new_surfaces)
.run_if(need_surface_configuration)
.before(prepare_windows),
)
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
@ -198,7 +201,7 @@ fn extract_windows(
struct SurfaceData {
// TODO: what lifetime should this be?
surface: wgpu::Surface<'static>,
format: TextureFormat,
configuration: SurfaceConfiguration,
}
#[derive(Resource, Default)]
@ -215,6 +218,9 @@ impl WindowSurfaces {
}
}
#[cfg(target_os = "linux")]
const NVIDIA_VENDOR_ID: u32 = 0x10DE;
/// (re)configures window surfaces, and obtains a swapchain texture for rendering.
///
/// NOTE: `get_current_texture` in `prepare_windows` can take a long time if the GPU workload is
@ -254,45 +260,12 @@ pub fn prepare_windows(
continue;
};
let surface_configuration = wgpu::SurfaceConfiguration {
format: surface_data.format,
width: window.physical_width,
height: window.physical_height,
usage: TextureUsages::RENDER_ATTACHMENT,
present_mode: match window.present_mode {
PresentMode::Fifo => wgpu::PresentMode::Fifo,
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
PresentMode::Immediate => wgpu::PresentMode::Immediate,
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
},
// TODO: Expose this as a setting somewhere
// 2 is wgpu's default/what we've been using so far.
// 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish
// all work for the previous frame before starting work on the next frame, which then means the gpu
// has to wait for the cpu to finish to start on the next frame.
desired_maximum_frame_latency: 2,
alpha_mode: match window.alpha_mode {
CompositeAlphaMode::Auto => wgpu::CompositeAlphaMode::Auto,
CompositeAlphaMode::Opaque => wgpu::CompositeAlphaMode::Opaque,
CompositeAlphaMode::PreMultiplied => wgpu::CompositeAlphaMode::PreMultiplied,
CompositeAlphaMode::PostMultiplied => wgpu::CompositeAlphaMode::PostMultiplied,
CompositeAlphaMode::Inherit => wgpu::CompositeAlphaMode::Inherit,
},
view_formats: if !surface_data.format.is_srgb() {
vec![surface_data.format.add_srgb_suffix()]
} else {
vec![]
},
};
// This is an ugly hack to work around drivers that don't support MSAA.
// This should be removed once https://github.com/bevyengine/bevy/issues/7194 lands and we're doing proper
// feature detection for MSAA.
// When removed, we can also remove the `.after(prepare_windows)` of `prepare_core_3d_depth_textures` and `prepare_prepass_textures`
let sample_flags = render_adapter
.get_texture_format_features(surface_configuration.format)
.get_texture_format_features(surface_data.configuration.format)
.flags;
if !sample_flags.sample_count_supported(msaa.samples()) {
@ -336,22 +309,43 @@ pub fn prepare_windows(
})
};
#[cfg(target_os = "linux")]
let is_nvidia = || {
render_instance
.enumerate_adapters(wgpu::Backends::VULKAN)
.iter()
.any(|adapter| adapter.get_info().vendor & 0xFFFF == NVIDIA_VENDOR_ID)
};
let not_already_configured = window_surfaces.configured_windows.insert(window.entity);
let surface = &surface_data.surface;
if not_already_configured || window.size_changed || window.present_mode_changed {
render_device.configure_surface(surface, &surface_configuration);
let frame = surface
.get_current_texture()
.expect("Error configuring surface");
window.set_swapchain_texture(frame);
match surface.get_current_texture() {
Ok(frame) => window.set_swapchain_texture(frame),
#[cfg(target_os = "linux")]
Err(wgpu::SurfaceError::Outdated) if is_nvidia() => {
warn_once!(
"Couldn't get swap chain texture. This often happens with \
the NVIDIA drivers on Linux. It can be safely ignored."
);
}
Err(err) => panic!("Error configuring surface: {err}"),
};
} else {
match surface.get_current_texture() {
Ok(frame) => {
window.set_swapchain_texture(frame);
}
#[cfg(target_os = "linux")]
Err(wgpu::SurfaceError::Outdated) if is_nvidia() => {
warn_once!(
"Couldn't get swap chain texture. This often happens with \
the Nvidia 550 driver. It can be safely ignored."
);
}
Err(wgpu::SurfaceError::Outdated) => {
render_device.configure_surface(surface, &surface_configuration);
render_device.configure_surface(surface, &surface_data.configuration);
let frame = surface
.get_current_texture()
.expect("Error reconfiguring surface");
@ -369,20 +363,20 @@ pub fn prepare_windows(
}
}
};
window.swap_chain_texture_format = Some(surface_data.format);
window.swap_chain_texture_format = Some(surface_data.configuration.format);
if window.screenshot_func.is_some() {
let texture = render_device.create_texture(&wgpu::TextureDescriptor {
label: Some("screenshot-capture-rendertarget"),
size: wgpu::Extent3d {
width: surface_configuration.width,
height: surface_configuration.height,
width: surface_data.configuration.width,
height: surface_data.configuration.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: surface_configuration.format.add_srgb_suffix(),
format: surface_data.configuration.format.add_srgb_suffix(),
usage: TextureUsages::RENDER_ATTACHMENT
| TextureUsages::COPY_SRC
| TextureUsages::TEXTURE_BINDING,
@ -394,7 +388,7 @@ pub fn prepare_windows(
size: screenshot::get_aligned_size(
window.physical_width,
window.physical_height,
surface_data.format.pixel_size() as u32,
surface_data.configuration.format.pixel_size() as u32,
) as u64,
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
mapped_at_creation: false,
@ -407,7 +401,7 @@ pub fn prepare_windows(
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&screenshot_pipeline,
surface_configuration.format,
surface_data.configuration.format,
);
window.swap_chain_texture_view = Some(texture_view);
window.screenshot_memory = Some(ScreenshotPreparedState {
@ -420,12 +414,15 @@ pub fn prepare_windows(
}
}
pub fn need_new_surfaces(
pub fn need_surface_configuration(
windows: Res<ExtractedWindows>,
window_surfaces: Res<WindowSurfaces>,
) -> bool {
for window in windows.windows.values() {
if !window_surfaces.configured_windows.contains(&window.entity) {
if !window_surfaces.configured_windows.contains(&window.entity)
|| window.size_changed
|| window.present_mode_changed
{
return true;
}
}
@ -443,9 +440,10 @@ pub fn create_surfaces(
mut window_surfaces: ResMut<WindowSurfaces>,
render_instance: Res<RenderInstance>,
render_adapter: Res<RenderAdapter>,
render_device: Res<RenderDevice>,
) {
for window in windows.windows.values() {
window_surfaces
let data = window_surfaces
.surfaces
.entry(window.entity)
.or_insert_with(|| {
@ -477,7 +475,63 @@ pub fn create_surfaces(
}
}
SurfaceData { surface, format }
let configuration = wgpu::SurfaceConfiguration {
format,
width: window.physical_width,
height: window.physical_height,
usage: TextureUsages::RENDER_ATTACHMENT,
present_mode: match window.present_mode {
PresentMode::Fifo => wgpu::PresentMode::Fifo,
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
PresentMode::Immediate => wgpu::PresentMode::Immediate,
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
},
// TODO: Expose this as a setting somewhere
// 2 is wgpu's default/what we've been using so far.
// 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish
// all work for the previous frame before starting work on the next frame, which then means the gpu
// has to wait for the cpu to finish to start on the next frame.
desired_maximum_frame_latency: 2,
alpha_mode: match window.alpha_mode {
CompositeAlphaMode::Auto => wgpu::CompositeAlphaMode::Auto,
CompositeAlphaMode::Opaque => wgpu::CompositeAlphaMode::Opaque,
CompositeAlphaMode::PreMultiplied => {
wgpu::CompositeAlphaMode::PreMultiplied
}
CompositeAlphaMode::PostMultiplied => {
wgpu::CompositeAlphaMode::PostMultiplied
}
CompositeAlphaMode::Inherit => wgpu::CompositeAlphaMode::Inherit,
},
view_formats: if !format.is_srgb() {
vec![format.add_srgb_suffix()]
} else {
vec![]
},
};
render_device.configure_surface(&surface, &configuration);
SurfaceData {
surface,
configuration,
}
});
if window.size_changed || window.present_mode_changed {
data.configuration.width = window.physical_width;
data.configuration.height = window.physical_height;
data.configuration.present_mode = match window.present_mode {
PresentMode::Fifo => wgpu::PresentMode::Fifo,
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
PresentMode::Immediate => wgpu::PresentMode::Immediate,
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
};
render_device.configure_surface(&data.surface, &data.configuration);
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_scene"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides scene functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,17 +14,17 @@ serialize = ["dep:serde", "uuid/serde"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.0", optional = true }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_render = { path = "../bevy_render", version = "0.13.2", optional = true }
# other
serde = { version = "1.0", features = ["derive"], optional = true }

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_sprite"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides sprite functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,19 +14,19 @@ webgpu = []
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
# other
bytemuck = { version = "1.5", features = ["derive"] }

View File

@ -32,6 +32,8 @@ pub struct Sprite {
}
/// Controls how the image is altered when scaled.
///
/// Note: This is not yet compatible with texture atlases
#[derive(Component, Debug, Clone, Reflect)]
#[reflect(Component)]
pub enum ImageScaleMode {

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_tasks"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "A task executor for Bevy Engine"
homepage = "https://bevyengine.org"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_text"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides text functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,18 +14,18 @@ default_font = []
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.2" }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
ab_glyph = "0.2.6"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_time"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides time functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -15,14 +15,14 @@ bevy_ci_testing = ["bevy_app/bevy_ci_testing"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2", features = [
"bevy_reflect",
] }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
crossbeam-channel = "0.5.0"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_transform"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides transform functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,21 +10,21 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0", features = [
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2", features = [
"bevy_reflect",
] }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
serde = { version = "1", features = ["derive"], optional = true }
thiserror = "1.0"
[dev-dependencies]
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0", features = ["approx"] }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2", features = ["approx"] }
approx = "0.5.1"
[features]

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_ui"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "A custom ECS-driven UI framework built specifically for Bevy Engine"
homepage = "https://bevyengine.org"
@ -10,25 +10,25 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_input = { path = "../bevy_input", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_a11y = { path = "../bevy_a11y", version = "0.13.2" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_asset = { path = "../bevy_asset", version = "0.13.2" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_input = { path = "../bevy_input", version = "0.13.2" }
bevy_log = { path = "../bevy_log", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"bevy",
] }
bevy_render = { path = "../bevy_render", version = "0.13.0" }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.0" }
bevy_text = { path = "../bevy_text", version = "0.13.0", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_render = { path = "../bevy_render", version = "0.13.2" }
bevy_sprite = { path = "../bevy_sprite", version = "0.13.2" }
bevy_text = { path = "../bevy_text", version = "0.13.2", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# other
taffy = { version = "0.3.10" }

View File

@ -251,9 +251,16 @@ pub fn ui_focus_system(
// The mouse position relative to the node
// (0., 0.) is the top-left corner, (1., 1.) is the bottom-right corner
// Coordinates are relative to the entire node, not just the visible region.
let relative_cursor_position = camera_cursor_positions
.get(&camera_entity)
.map(|cursor_position| (*cursor_position - node_rect.min) / node_rect.size());
let relative_cursor_position =
camera_cursor_positions
.get(&camera_entity)
.and_then(|cursor_position| {
// ensure node size is non-zero in all dimensions, otherwise relative position will be
// +/-inf. if the node is hidden, the visible rect min/max will also be -inf leading to
// false positives for mouse_over (#12395)
(node_rect.size().cmpgt(Vec2::ZERO).all())
.then_some((*cursor_position - node_rect.min) / node_rect.size())
});
// If the current cursor position is within the bounds of the node's visible area, consider it for
// clicking

View File

@ -2,14 +2,13 @@ mod convert;
pub mod debug;
use crate::{ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiScale};
use bevy_ecs::entity::EntityHashMap;
use bevy_ecs::{
change_detection::{DetectChanges, DetectChangesMut},
entity::Entity,
entity::{Entity, EntityHashMap},
event::EventReader,
query::{With, Without},
removal_detection::RemovedComponents,
system::{Query, Res, ResMut, Resource},
system::{Query, Res, ResMut, Resource, SystemParam},
world::Ref,
};
use bevy_hierarchy::{Children, Parent};
@ -53,6 +52,7 @@ struct RootNodePair {
#[derive(Resource)]
pub struct UiSurface {
entity_to_taffy: EntityHashMap<taffy::node::Node>,
camera_entity_to_taffy: EntityHashMap<EntityHashMap<taffy::node::Node>>,
camera_roots: EntityHashMap<Vec<RootNodePair>>,
taffy: Taffy,
}
@ -79,6 +79,7 @@ impl Default for UiSurface {
taffy.disable_rounding();
Self {
entity_to_taffy: Default::default(),
camera_entity_to_taffy: Default::default(),
camera_roots: Default::default(),
taffy,
}
@ -167,6 +168,7 @@ without UI components as a child of an entity with UI components, results may be
..default()
};
let camera_root_node_map = self.camera_entity_to_taffy.entry(camera_id).or_default();
let existing_roots = self.camera_roots.entry(camera_id).or_default();
let mut new_roots = Vec::new();
for entity in children {
@ -181,24 +183,19 @@ without UI components as a child of an entity with UI components, results may be
self.taffy.remove_child(previous_parent, node).unwrap();
}
let viewport_node = *camera_root_node_map
.entry(entity)
.or_insert_with(|| self.taffy.new_leaf(viewport_style.clone()).unwrap());
self.taffy.add_child(viewport_node, node).unwrap();
RootNodePair {
implicit_viewport_node: self
.taffy
.new_with_children(viewport_style.clone(), &[node])
.unwrap(),
implicit_viewport_node: viewport_node,
user_root_node: node,
}
});
new_roots.push(root_node);
}
// Cleanup the implicit root nodes of any user root nodes that have been removed
for old_root in existing_roots {
if !new_roots.contains(old_root) {
self.taffy.remove(old_root.implicit_viewport_node).unwrap();
}
}
self.camera_roots.insert(camera_id, new_roots);
}
@ -219,6 +216,17 @@ without UI components as a child of an entity with UI components, results may be
}
}
/// Removes each camera entity from the internal map and then removes their associated node from taffy
pub fn remove_camera_entities(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
if let Some(camera_root_node_map) = self.camera_entity_to_taffy.remove(&entity) {
for (_, node) in camera_root_node_map.iter() {
self.taffy.remove(*node).unwrap();
}
}
}
}
/// Removes each entity from the internal map and then removes their associated node from taffy
pub fn remove_entities(&mut self, entities: impl IntoIterator<Item = Entity>) {
for entity in entities {
@ -253,6 +261,14 @@ pub enum LayoutError {
TaffyError(#[from] taffy::error::TaffyError),
}
#[derive(SystemParam)]
pub struct UiLayoutSystemRemovedComponentParam<'w, 's> {
removed_cameras: RemovedComponents<'w, 's, Camera>,
removed_children: RemovedComponents<'w, 's, Children>,
removed_content_sizes: RemovedComponents<'w, 's, ContentSize>,
removed_nodes: RemovedComponents<'w, 's, Node>,
}
/// Updates the UI's layout tree, computes the new layout geometry and then updates the sizes and transforms of all the UI nodes.
#[allow(clippy::too_many_arguments)]
pub fn ui_layout_system(
@ -268,9 +284,7 @@ pub fn ui_layout_system(
mut measure_query: Query<(Entity, &mut ContentSize)>,
children_query: Query<(Entity, Ref<Children>), With<Node>>,
just_children_query: Query<&Children>,
mut removed_children: RemovedComponents<Children>,
mut removed_content_sizes: RemovedComponents<ContentSize>,
mut removed_nodes: RemovedComponents<Node>,
mut removed_components: UiLayoutSystemRemovedComponentParam,
mut node_transform_query: Query<(&mut Node, &mut Transform)>,
) {
struct CameraLayoutInfo {
@ -357,7 +371,7 @@ pub fn ui_layout_system(
scale_factor_events.clear();
// When a `ContentSize` component is removed from an entity, we need to remove the measure from the corresponding taffy node.
for entity in removed_content_sizes.read() {
for entity in removed_components.removed_content_sizes.read() {
ui_surface.try_remove_measure(entity);
}
for (entity, mut content_size) in &mut measure_query {
@ -367,15 +381,24 @@ pub fn ui_layout_system(
}
// clean up removed nodes
ui_surface.remove_entities(removed_nodes.read());
ui_surface.remove_entities(removed_components.removed_nodes.read());
// clean up removed cameras
ui_surface.remove_camera_entities(removed_components.removed_cameras.read());
// update camera children
for (camera_id, CameraLayoutInfo { root_nodes, .. }) in &camera_layout_info {
ui_surface.set_camera_children(*camera_id, root_nodes.iter().cloned());
for (camera_id, _) in cameras.iter() {
let root_nodes =
if let Some(CameraLayoutInfo { root_nodes, .. }) = camera_layout_info.get(&camera_id) {
root_nodes.iter().cloned()
} else {
[].iter().cloned()
};
ui_surface.set_camera_children(camera_id, root_nodes);
}
// update and remove children
for entity in removed_children.read() {
for entity in removed_components.removed_children.read() {
ui_surface.try_remove_children(entity);
}
for (entity, children) in &children_query {
@ -411,7 +434,9 @@ pub fn ui_layout_system(
mut absolute_location: Vec2,
) {
if let Ok((mut node, mut transform)) = node_transform_query.get_mut(entity) {
let layout = ui_surface.get_layout(entity).unwrap();
let Ok(layout) = ui_surface.get_layout(entity) else {
return;
};
let layout_size =
inverse_target_scale_factor * Vec2::new(layout.size.width, layout.size.height);
let layout_location =
@ -519,18 +544,20 @@ mod tests {
use bevy_core_pipeline::core_2d::Camera2dBundle;
use bevy_ecs::entity::Entity;
use bevy_ecs::event::Events;
use bevy_ecs::prelude::{Commands, Component, In, Query, With};
use bevy_ecs::query::Without;
use bevy_ecs::schedule::apply_deferred;
use bevy_ecs::schedule::IntoSystemConfigs;
use bevy_ecs::schedule::Schedule;
use bevy_ecs::system::RunSystemOnce;
use bevy_ecs::world::World;
use bevy_hierarchy::despawn_with_children_recursive;
use bevy_hierarchy::BuildWorldChildren;
use bevy_hierarchy::Children;
use bevy_math::vec2;
use bevy_math::Vec2;
use bevy_hierarchy::{despawn_with_children_recursive, BuildWorldChildren, Children, Parent};
use bevy_math::{vec2, Rect, UVec2, Vec2};
use bevy_render::camera::ManualTextureViews;
use bevy_render::camera::OrthographicProjection;
use bevy_render::prelude::Camera;
use bevy_render::texture::Image;
use bevy_transform::prelude::{GlobalTransform, Transform};
use bevy_utils::prelude::default;
use bevy_utils::HashMap;
use bevy_window::PrimaryWindow;
@ -655,6 +682,54 @@ mod tests {
assert!(ui_surface.entity_to_taffy.is_empty());
}
#[test]
fn ui_surface_tracks_camera_entities() {
let (mut world, mut ui_schedule) = setup_ui_test_world();
// despawn all cameras so we can reset ui_surface back to a fresh state
let camera_entities = world
.query_filtered::<Entity, With<Camera>>()
.iter(&world)
.collect::<Vec<_>>();
for camera_entity in camera_entities {
world.despawn(camera_entity);
}
ui_schedule.run(&mut world);
// no UI entities in world, none in UiSurface
let ui_surface = world.resource::<UiSurface>();
assert!(ui_surface.camera_entity_to_taffy.is_empty());
// respawn camera
let camera_entity = world.spawn(Camera2dBundle::default()).id();
let ui_entity = world
.spawn((NodeBundle::default(), TargetCamera(camera_entity)))
.id();
// `ui_layout_system` should map `camera_entity` to a ui node in `UiSurface::camera_entity_to_taffy`
ui_schedule.run(&mut world);
let ui_surface = world.resource::<UiSurface>();
assert!(ui_surface
.camera_entity_to_taffy
.contains_key(&camera_entity));
assert_eq!(ui_surface.camera_entity_to_taffy.len(), 1);
world.despawn(ui_entity);
world.despawn(camera_entity);
// `ui_layout_system` should remove `camera_entity` from `UiSurface::camera_entity_to_taffy`
ui_schedule.run(&mut world);
let ui_surface = world.resource::<UiSurface>();
assert!(!ui_surface
.camera_entity_to_taffy
.contains_key(&camera_entity));
assert!(ui_surface.camera_entity_to_taffy.is_empty());
}
#[test]
#[should_panic]
fn despawning_a_ui_entity_should_remove_its_corresponding_ui_node() {
@ -783,6 +858,232 @@ mod tests {
assert!(ui_surface.entity_to_taffy.is_empty());
}
/// regression test for >=0.13.1 root node layouts
/// ensure root nodes act like they are absolutely positioned
/// without explicitly declaring it.
#[test]
fn ui_root_node_should_act_like_position_absolute() {
let (mut world, mut ui_schedule) = setup_ui_test_world();
let mut size = 150.;
world.spawn(NodeBundle {
style: Style {
// test should pass without explicitly requiring position_type to be set to Absolute
// position_type: PositionType::Absolute,
width: Val::Px(size),
height: Val::Px(size),
..default()
},
..default()
});
size -= 50.;
world.spawn(NodeBundle {
style: Style {
// position_type: PositionType::Absolute,
width: Val::Px(size),
height: Val::Px(size),
..default()
},
..default()
});
size -= 50.;
world.spawn(NodeBundle {
style: Style {
// position_type: PositionType::Absolute,
width: Val::Px(size),
height: Val::Px(size),
..default()
},
..default()
});
ui_schedule.run(&mut world);
let overlap_check = world
.query_filtered::<(Entity, &Node, &mut GlobalTransform, &Transform), Without<Parent>>()
.iter_mut(&mut world)
.fold(
Option::<(Rect, bool)>::None,
|option_rect, (entity, node, mut global_transform, transform)| {
// fix global transform - for some reason the global transform isn't populated yet.
// might be related to how these specific tests are working directly with World instead of App
*global_transform = GlobalTransform::from(transform.compute_affine());
let global_transform = &*global_transform;
let current_rect = node.logical_rect(global_transform);
assert!(
current_rect.height().abs() + current_rect.width().abs() > 0.,
"root ui node {entity:?} doesn't have a logical size"
);
assert_ne!(
global_transform.affine(),
GlobalTransform::default().affine(),
"root ui node {entity:?} global transform is not populated"
);
let Some((rect, is_overlapping)) = option_rect else {
return Some((current_rect, false));
};
if rect.contains(current_rect.center()) {
Some((current_rect, true))
} else {
Some((current_rect, is_overlapping))
}
},
);
let Some((_rect, is_overlapping)) = overlap_check else {
unreachable!("test not setup properly");
};
assert!(is_overlapping, "root ui nodes are expected to behave like they have absolute position and be independent from each other");
}
#[test]
fn ui_node_should_properly_update_when_changing_target_camera() {
#[derive(Component)]
struct MovingUiNode;
fn update_camera_viewports(
primary_window_query: Query<&Window, With<PrimaryWindow>>,
mut cameras: Query<&mut Camera>,
) {
let primary_window = primary_window_query
.get_single()
.expect("missing primary window");
let camera_count = cameras.iter().len();
for (camera_index, mut camera) in cameras.iter_mut().enumerate() {
let viewport_width =
primary_window.resolution.physical_width() / camera_count as u32;
let viewport_height = primary_window.resolution.physical_height();
let physical_position = UVec2::new(viewport_width * camera_index as u32, 0);
let physical_size = UVec2::new(viewport_width, viewport_height);
camera.viewport = Some(bevy_render::camera::Viewport {
physical_position,
physical_size,
..default()
});
}
}
fn move_ui_node(
In(pos): In<Vec2>,
mut commands: Commands,
cameras: Query<(Entity, &Camera)>,
moving_ui_query: Query<Entity, With<MovingUiNode>>,
) {
let (target_camera_entity, _) = cameras
.iter()
.find(|(_, camera)| {
let Some(logical_viewport_rect) = camera.logical_viewport_rect() else {
panic!("missing logical viewport")
};
// make sure cursor is in viewport and that viewport has at least 1px of size
logical_viewport_rect.contains(pos)
&& logical_viewport_rect.max.cmpge(Vec2::splat(0.)).any()
})
.expect("cursor position outside of camera viewport");
for moving_ui_entity in moving_ui_query.iter() {
commands
.entity(moving_ui_entity)
.insert(TargetCamera(target_camera_entity))
.insert(Style {
position_type: PositionType::Absolute,
top: Val::Px(pos.y),
left: Val::Px(pos.x),
..default()
});
}
}
fn do_move_and_test(
world: &mut World,
ui_schedule: &mut Schedule,
new_pos: Vec2,
expected_camera_entity: &Entity,
) {
world.run_system_once_with(new_pos, move_ui_node);
ui_schedule.run(world);
let (ui_node_entity, TargetCamera(target_camera_entity)) = world
.query_filtered::<(Entity, &TargetCamera), With<MovingUiNode>>()
.get_single(world)
.expect("missing MovingUiNode");
assert_eq!(expected_camera_entity, target_camera_entity);
let ui_surface = world.resource::<UiSurface>();
let layout = ui_surface
.get_layout(ui_node_entity)
.expect("failed to get layout");
// negative test for #12255
assert_eq!(Vec2::new(layout.location.x, layout.location.y), new_pos);
}
fn get_taffy_node_count(world: &World) -> usize {
world.resource::<UiSurface>().taffy.total_node_count()
}
let (mut world, mut ui_schedule) = setup_ui_test_world();
world.spawn(Camera2dBundle {
camera: Camera {
order: 1,
..default()
},
..default()
});
world.spawn((
NodeBundle {
style: Style {
position_type: PositionType::Absolute,
top: Val::Px(0.),
left: Val::Px(0.),
..default()
},
..default()
},
MovingUiNode,
));
ui_schedule.run(&mut world);
let pos_inc = Vec2::splat(1.);
let total_cameras = world.query::<&Camera>().iter(&world).len();
// add total cameras - 1 (the assumed default) to get an idea for how many nodes we should expect
let expected_max_taffy_node_count = get_taffy_node_count(&world) + total_cameras - 1;
world.run_system_once(update_camera_viewports);
ui_schedule.run(&mut world);
let viewport_rects = world
.query::<(Entity, &Camera)>()
.iter(&world)
.map(|(e, c)| (e, c.logical_viewport_rect().expect("missing viewport")))
.collect::<Vec<_>>();
for (camera_entity, viewport) in viewport_rects.iter() {
let target_pos = viewport.min + pos_inc;
do_move_and_test(&mut world, &mut ui_schedule, target_pos, camera_entity);
}
// reverse direction
let mut viewport_rects = viewport_rects.clone();
viewport_rects.reverse();
for (camera_entity, viewport) in viewport_rects.iter() {
let target_pos = viewport.max - pos_inc;
do_move_and_test(&mut world, &mut ui_schedule, target_pos, camera_entity);
}
let current_taffy_node_count = get_taffy_node_count(&world);
if current_taffy_node_count > expected_max_taffy_node_count {
panic!("extra taffy nodes detected: current: {current_taffy_node_count} max expected: {expected_max_taffy_node_count}");
}
}
#[test]
fn ui_node_should_be_set_to_its_content_size() {
let (mut world, mut ui_schedule) = setup_ui_test_world();

View File

@ -596,10 +596,13 @@ pub fn extract_text_uinodes(
// * Multiply by the rounded physical position by the inverse scale factor to return to logical coordinates
let logical_top_left = -0.5 * uinode.size();
let physical_nearest_pixel = (logical_top_left * scale_factor).round();
let logical_top_left_nearest_pixel = physical_nearest_pixel * inverse_scale_factor;
let transform = Mat4::from(global_transform.affine())
* Mat4::from_translation(logical_top_left_nearest_pixel.extend(0.));
let mut transform = global_transform.affine()
* bevy_math::Affine3A::from_translation(logical_top_left.extend(0.));
transform.translation *= scale_factor;
transform.translation = transform.translation.round();
transform.translation *= inverse_scale_factor;
let mut color = Color::WHITE;
let mut current_section = usize::MAX;

View File

@ -10,7 +10,7 @@ use bevy_sprite::{ImageScaleMode, TextureSlice};
use bevy_transform::prelude::*;
use bevy_utils::HashSet;
use crate::{widget::UiImageSize, BackgroundColor, CalculatedClip, ExtractedUiNode, Node, UiImage};
use crate::{BackgroundColor, CalculatedClip, ExtractedUiNode, Node, UiImage};
/// Component storing texture slices for image nodes entities with a tiled or sliced [`ImageScaleMode`]
///
@ -119,13 +119,7 @@ pub(crate) fn compute_slices_on_asset_event(
mut commands: Commands,
mut events: EventReader<AssetEvent<Image>>,
images: Res<Assets<Image>>,
ui_nodes: Query<(
Entity,
&ImageScaleMode,
&Node,
Option<&UiImageSize>,
&UiImage,
)>,
ui_nodes: Query<(Entity, &ImageScaleMode, &Node, &UiImage)>,
) {
// We store the asset ids of added/modified image assets
let added_handles: HashSet<_> = events
@ -139,12 +133,11 @@ pub(crate) fn compute_slices_on_asset_event(
return;
}
// We recompute the sprite slices for sprite entities with a matching asset handle id
for (entity, scale_mode, ui_node, size, image) in &ui_nodes {
for (entity, scale_mode, ui_node, image) in &ui_nodes {
if !added_handles.contains(&image.texture.id()) {
continue;
}
let size = size.map(|s| s.size()).unwrap_or(ui_node.size());
if let Some(slices) = compute_texture_slices(size, scale_mode, image, &images) {
if let Some(slices) = compute_texture_slices(ui_node.size(), scale_mode, image, &images) {
commands.entity(entity).insert(slices);
}
}
@ -156,24 +149,12 @@ pub(crate) fn compute_slices_on_image_change(
mut commands: Commands,
images: Res<Assets<Image>>,
changed_nodes: Query<
(
Entity,
&ImageScaleMode,
&Node,
Option<&UiImageSize>,
&UiImage,
),
Or<(
Changed<ImageScaleMode>,
Changed<UiImage>,
Changed<UiImageSize>,
Changed<Node>,
)>,
(Entity, &ImageScaleMode, &Node, &UiImage),
Or<(Changed<ImageScaleMode>, Changed<UiImage>, Changed<Node>)>,
>,
) {
for (entity, scale_mode, ui_node, size, image) in &changed_nodes {
let size = size.map(|s| s.size()).unwrap_or(ui_node.size());
if let Some(slices) = compute_texture_slices(size, scale_mode, image, &images) {
for (entity, scale_mode, ui_node, image) in &changed_nodes {
if let Some(slices) = compute_texture_slices(ui_node.size(), scale_mode, image, &images) {
commands.entity(entity).insert(slices);
}
}

View File

@ -155,7 +155,9 @@ fn update_children_target_camera(
for &child in children {
// Skip if the child has already been updated or update is not needed
if updated_entities.contains(&child) || camera_to_set == node_query.get(child).unwrap() {
if updated_entities.contains(&child)
|| camera_to_set == node_query.get(child).ok().flatten()
{
continue;
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_utils"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "A collection of utils for Bevy Engine"
homepage = "https://bevyengine.org"
@ -17,7 +17,7 @@ tracing = { version = "0.1", default-features = false, features = ["std"] }
web-time = { version = "0.2" }
uuid = { version = "1.1", features = ["v4", "serde"] }
hashbrown = { version = "0.14", features = ["serde"] }
bevy_utils_proc_macros = { version = "0.13.0", path = "macros" }
bevy_utils_proc_macros = { version = "0.13.2", path = "macros" }
petgraph = "0.6"
thiserror = "1.0"
nonmax = "0.5"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_utils_proc_macros"
version = "0.13.0"
version = "0.13.2"
description = "Bevy Utils Proc Macros"
edition = "2021"
license = "MIT OR Apache-2.0"

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_window"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "Provides windowing functionality for Bevy Engine"
homepage = "https://bevyengine.org"
@ -14,16 +14,16 @@ serialize = ["serde", "smol_str/serde"]
[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
bevy_a11y = { path = "../bevy_a11y", version = "0.13.2" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.2", features = [
"glam",
] }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
# Used for close_on_esc
bevy_input = { path = "../bevy_input", version = "0.13.0" }
bevy_input = { path = "../bevy_input", version = "0.13.2" }
# other
serde = { version = "1.0", features = ["derive"], optional = true }

View File

@ -648,7 +648,7 @@ impl WindowResolution {
/// Builder method for adding a scale factor override to the resolution.
pub fn with_scale_factor_override(mut self, scale_factor_override: f32) -> Self {
self.scale_factor_override = Some(scale_factor_override);
self.set_scale_factor_override(Some(scale_factor_override));
self
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_winit"
version = "0.13.0"
version = "0.13.2"
edition = "2021"
description = "A winit window and input backend for Bevy Engine"
homepage = "https://bevyengine.org"
@ -16,16 +16,16 @@ accesskit_unix = ["accesskit_winit/accesskit_unix", "accesskit_winit/async-io"]
[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.13.0" }
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_derive = { path = "../bevy_derive", version = "0.13.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }
bevy_input = { path = "../bevy_input", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_window = { path = "../bevy_window", version = "0.13.0" }
bevy_utils = { path = "../bevy_utils", version = "0.13.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.0" }
bevy_a11y = { path = "../bevy_a11y", version = "0.13.2" }
bevy_app = { path = "../bevy_app", version = "0.13.2" }
bevy_derive = { path = "../bevy_derive", version = "0.13.2" }
bevy_ecs = { path = "../bevy_ecs", version = "0.13.2" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.2" }
bevy_input = { path = "../bevy_input", version = "0.13.2" }
bevy_math = { path = "../bevy_math", version = "0.13.2" }
bevy_window = { path = "../bevy_window", version = "0.13.2" }
bevy_utils = { path = "../bevy_utils", version = "0.13.2" }
bevy_tasks = { path = "../bevy_tasks", version = "0.13.2" }
# other
# feature rwh_06 refers to window_raw_handle@v0.6

View File

@ -13,8 +13,9 @@ mod winit_windows;
use approx::relative_eq;
use bevy_a11y::AccessibilityRequested;
use bevy_utils::{Duration, Instant};
use system::{changed_windows, create_windows, despawn_windows, CachedWindow};
use bevy_utils::Instant;
pub use system::create_windows;
use system::{changed_windows, despawn_windows, CachedWindow};
use winit::dpi::{LogicalSize, PhysicalSize};
pub use winit_config::*;
pub use winit_windows::*;
@ -44,6 +45,7 @@ use bevy_window::{PrimaryWindow, RawHandleWrapper};
#[cfg(target_os = "android")]
pub use winit::platform::android::activity as android_activity;
use winit::event::StartCause;
use winit::{
event::{self, DeviceEvent, Event, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget},
@ -81,7 +83,7 @@ pub struct WinitPlugin {
impl Plugin for WinitPlugin {
fn build(&self, app: &mut App) {
let mut event_loop_builder = EventLoopBuilder::<()>::with_user_event();
let mut event_loop_builder = EventLoopBuilder::<UserEvent>::with_user_event();
// linux check is needed because x11 might be enabled on other platforms.
#[cfg(all(target_os = "linux", feature = "x11"))]
@ -181,8 +183,6 @@ struct WinitAppRunnerState {
wait_elapsed: bool,
/// The time the last update started.
last_update: Instant,
/// The time the next update is scheduled to start.
scheduled_update: Option<Instant>,
/// Number of "forced" updates to trigger on application start
startup_forced_updates: u32,
}
@ -223,14 +223,14 @@ impl Default for WinitAppRunnerState {
redraw_requested: false,
wait_elapsed: false,
last_update: Instant::now(),
scheduled_update: None,
// 3 seems to be enough, 5 is a safe margin
startup_forced_updates: 5,
}
}
}
type CreateWindowParams<'w, 's, F = ()> = (
/// The parameters of the [`create_windows`] system.
pub type CreateWindowParams<'w, 's, F = ()> = (
Commands<'w, 's>,
Query<'w, 's, (Entity, &'static mut Window), F>,
EventWriter<'w, WindowCreated>,
@ -240,6 +240,15 @@ type CreateWindowParams<'w, 's, F = ()> = (
Res<'w, AccessibilityRequested>,
);
/// The [`winit::event_loop::EventLoopProxy`] with the specific [`winit::event::Event::UserEvent`] used in the [`winit_runner`].
///
/// The `EventLoopProxy` can be used to request a redraw from outside bevy.
///
/// Use `NonSend<EventLoopProxy>` to receive this resource.
pub type EventLoopProxy = winit::event_loop::EventLoopProxy<UserEvent>;
type UserEvent = RequestRedraw;
/// The default [`App::runner`] for the [`WinitPlugin`] plugin.
///
/// Overriding the app's [runner](bevy_app::App::runner) while using `WinitPlugin` will bypass the
@ -252,7 +261,7 @@ pub fn winit_runner(mut app: App) {
let event_loop = app
.world
.remove_non_send_resource::<EventLoop<()>>()
.remove_non_send_resource::<EventLoop<UserEvent>>()
.unwrap();
app.world
@ -277,7 +286,7 @@ pub fn winit_runner(mut app: App) {
let mut create_window =
SystemState::<CreateWindowParams<Added<Window>>>::from_world(&mut app.world);
// set up the event loop
let event_handler = move |event, event_loop: &EventLoopWindowTarget<()>| {
let event_handler = move |event, event_loop: &EventLoopWindowTarget<UserEvent>| {
handle_winit_event(
&mut app,
&mut app_exit_event_reader,
@ -312,8 +321,8 @@ fn handle_winit_event(
)>,
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
event: Event<()>,
event_loop: &EventLoopWindowTarget<()>,
event: Event<UserEvent>,
event_loop: &EventLoopWindowTarget<UserEvent>,
) {
#[cfg(feature = "trace")]
let _span = bevy_utils::tracing::info_span!("winit event_handler").entered();
@ -395,12 +404,14 @@ fn handle_winit_event(
}
}
}
Event::NewEvents(_) => {
if let Some(t) = runner_state.scheduled_update {
let now = Instant::now();
let remaining = t.checked_duration_since(now).unwrap_or(Duration::ZERO);
runner_state.wait_elapsed = remaining.is_zero();
}
Event::NewEvents(cause) => {
runner_state.wait_elapsed = match cause {
StartCause::WaitCancelled {
requested_resume: Some(resume),
..
} => resume >= Instant::now(),
_ => true,
};
}
Event::WindowEvent {
event, window_id, ..
@ -690,6 +701,9 @@ fn handle_winit_event(
event_loop.set_control_flow(ControlFlow::Wait);
}
}
Event::UserEvent(RequestRedraw) => {
runner_state.redraw_requested = true;
}
_ => (),
}
}
@ -698,7 +712,7 @@ fn run_app_update_if_should(
runner_state: &mut WinitAppRunnerState,
app: &mut App,
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
event_loop: &EventLoopWindowTarget<()>,
event_loop: &EventLoopWindowTarget<UserEvent>,
create_window: &mut SystemState<CreateWindowParams<Added<Window>>>,
app_exit_event_reader: &mut ManualEventReader<AppExit>,
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
@ -732,6 +746,7 @@ fn run_app_update_if_should(
match config.update_mode(focused) {
UpdateMode::Continuous => {
runner_state.redraw_requested = true;
event_loop.set_control_flow(ControlFlow::Wait);
}
UpdateMode::Reactive { wait } | UpdateMode::ReactiveLowPower { wait } => {
// TODO(bug): this is unexpected behavior.
@ -740,10 +755,8 @@ fn run_app_update_if_should(
// Need to verify the plateform specifics (whether this can occur in
// rare-but-possible cases) and replace this with a panic or a log warn!
if let Some(next) = runner_state.last_update.checked_add(*wait) {
runner_state.scheduled_update = Some(next);
event_loop.set_control_flow(ControlFlow::WaitUntil(next));
} else {
runner_state.scheduled_update = None;
event_loop.set_control_flow(ControlFlow::Wait);
}
}

View File

@ -31,8 +31,8 @@ use crate::{
/// If any of these entities are missing required components, those will be added with their
/// default values.
#[allow(clippy::too_many_arguments)]
pub(crate) fn create_windows<F: QueryFilter + 'static>(
event_loop: &EventLoopWindowTarget<()>,
pub fn create_windows<F: QueryFilter + 'static>(
event_loop: &EventLoopWindowTarget<crate::UserEvent>,
(
mut commands,
mut created_windows,

View File

@ -28,6 +28,8 @@ impl WinitSettings {
///
/// [`Reactive`](UpdateMode::Reactive) if windows have focus,
/// [`ReactiveLowPower`](UpdateMode::ReactiveLowPower) otherwise.
///
/// Use the [`EventLoopProxy`](crate::EventLoopProxy) to request a redraw from outside bevy.
pub fn desktop_app() -> Self {
WinitSettings {
focused_mode: UpdateMode::Reactive {
@ -72,6 +74,7 @@ pub enum UpdateMode {
/// - a redraw has been requested by [`RequestRedraw`](bevy_window::RequestRedraw)
/// - new [window](`winit::event::WindowEvent`) or [raw input](`winit::event::DeviceEvent`)
/// events have appeared
/// - a redraw has been requested with the [`EventLoopProxy`](crate::EventLoopProxy)
Reactive {
/// The approximate time from the start of one update to the next.
///
@ -84,6 +87,7 @@ pub enum UpdateMode {
/// - `wait` time has elapsed since the previous update
/// - a redraw has been requested by [`RequestRedraw`](bevy_window::RequestRedraw)
/// - new [window events](`winit::event::WindowEvent`) have appeared
/// - a redraw has been requested with the [`EventLoopProxy`](crate::EventLoopProxy)
///
/// **Note:** Unlike [`Reactive`](`UpdateMode::Reactive`), this mode will ignore events that
/// don't come from interacting with a window, like [`MouseMotion`](winit::event::DeviceEvent::MouseMotion).

View File

@ -39,7 +39,7 @@ impl WinitWindows {
/// Creates a `winit` window and associates it with our entity.
pub fn create_window(
&mut self,
event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
event_loop: &winit::event_loop::EventLoopWindowTarget<crate::UserEvent>,
entity: Entity,
window: &Window,
adapters: &mut AccessKitAdapters,

View File

@ -239,13 +239,6 @@ ruby -run -ehttpd examples/wasm
Bevy support for WebGPU is being worked on, but is currently experimental.
To build for WebGPU, you'll need to enable the `webgpu` feature. This will override the `webgl2` feature, and builds with the `webgpu` feature enabled won't be able to run on browsers that don't support WebGPU.
WebGPU depends on unstable APIs so you will also need to pass the `web_sys_unstable_apis` flag to your builds. For example:
```sh
RUSTFLAGS=--cfg=web_sys_unstable_apis cargo build ...
```
Check `wasm-bindgen` [docs on Unstable APIs](https://rustwasm.github.io/wasm-bindgen/web-sys/unstable-apis.html) for more details.
Bevy has an helper to build its examples:

View File

@ -81,7 +81,7 @@ The default feature set enables most of the expected features of a game engine,
|trace_tracy_memory|Tracing support, with memory profiling, exposing a port for Tracy|
|wav|WAV audio format support|
|wayland|Wayland display server support|
|webgpu|Enable support for WebGPU in Wasm. When enabled, this feature will override the `webgl2` feature and you won't be able to run Wasm builds with WebGL2, only with WebGPU. Requires the `RUSTFLAGS` environment variable to be set to `--cfg=web_sys_unstable_apis` when building.|
|webgpu|Enable support for WebGPU in Wasm. When enabled, this feature will override the `webgl2` feature and you won't be able to run Wasm builds with WebGL2, only with WebGPU.|
|webp|WebP image format support|
|wgpu_trace|Save a trace of all wgpu calls|
|zlib|For KTX2 supercompression|

View File

@ -16,8 +16,9 @@ use bevy::{
render_resource::{
BlendState, ColorTargetState, ColorWrites, Face, FragmentState, FrontFace,
MultisampleState, PipelineCache, PolygonMode, PrimitiveState, PrimitiveTopology,
RenderPipelineDescriptor, SpecializedRenderPipeline, SpecializedRenderPipelines,
TextureFormat, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode,
PushConstantRange, RenderPipelineDescriptor, ShaderStages, SpecializedRenderPipeline,
SpecializedRenderPipelines, TextureFormat, VertexBufferLayout, VertexFormat,
VertexState, VertexStepMode,
},
texture::BevyDefault,
view::{ExtractedView, ViewTarget, VisibleEntities},
@ -157,6 +158,18 @@ impl SpecializedRenderPipeline for ColoredMesh2dPipeline {
false => TextureFormat::bevy_default(),
};
let mut push_constant_ranges = Vec::with_capacity(1);
if cfg!(all(
feature = "webgl2",
target_arch = "wasm32",
not(feature = "webgpu")
)) {
push_constant_ranges.push(PushConstantRange {
stages: ShaderStages::VERTEX,
range: 0..4,
});
}
RenderPipelineDescriptor {
vertex: VertexState {
// Use our custom shader
@ -184,7 +197,7 @@ impl SpecializedRenderPipeline for ColoredMesh2dPipeline {
// Bind group 1 is the mesh uniform
self.mesh2d_pipeline.mesh_layout.clone(),
],
push_constant_ranges: Vec::new(),
push_constant_ranges,
primitive: PrimitiveState {
front_face: FrontFace::Ccw,
cull_mode: Some(Face::Back),

View File

@ -35,19 +35,20 @@ fn setup_scene(
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
},
BloomSettings::default(), // 3. Enable bloom for the camera
// 3. Enable bloom for the camera
BloomSettings::NATURAL,
));
let material_emissive1 = materials.add(StandardMaterial {
emissive: Color::rgb_linear(2300.0, 900.0, 300.0), // 4. Put something bright in a dark environment to see the effect
emissive: Color::rgb_linear(23000.0, 9000.0, 3000.0), // 4. Put something bright in a dark environment to see the effect
..default()
});
let material_emissive2 = materials.add(StandardMaterial {
emissive: Color::rgb_linear(300.0, 2300.0, 900.0),
emissive: Color::rgb_linear(3000.0, 23000.0, 9000.0),
..default()
});
let material_emissive3 = materials.add(StandardMaterial {
emissive: Color::rgb_linear(900.0, 300.0, 2300.0),
emissive: Color::rgb_linear(9000.0, 3000.0, 23000.0),
..default()
});
let material_non_emissive = materials.add(StandardMaterial {
@ -59,6 +60,8 @@ fn setup_scene(
for x in -5..5 {
for z in -5..5 {
// This generates a pseudo-random integer between `[0, 6)`, but deterministically so
// the same spheres are always the same colors.
let mut hasher = DefaultHasher::new();
(x, z).hash(&mut hasher);
let rand = (hasher.finish() - 2) % 6;
@ -89,7 +92,7 @@ fn setup_scene(
"",
TextStyle {
font_size: 20.0,
color: Color::BLACK,
color: Color::WHITE,
..default()
},
)
@ -218,7 +221,7 @@ fn update_bloom_settings(
*text = "Bloom: Off (Toggle: Space)".to_string();
if keycode.just_pressed(KeyCode::Space) {
commands.entity(entity).insert(BloomSettings::default());
commands.entity(entity).insert(BloomSettings::NATURAL);
}
}
}

Some files were not shown because too many files have changed in this diff Show More