Merge branch 'bevyengine:main' into issue-16334-asset-get-many

This commit is contained in:
Wuketuke 2025-06-26 20:27:07 +00:00 committed by GitHub
commit 151f365427
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
615 changed files with 18847 additions and 6517 deletions

View File

@ -15,7 +15,7 @@ env:
# If nightly is breaking CI, modify this variable to target a specific nightly version.
NIGHTLY_TOOLCHAIN: nightly
RUSTFLAGS: "-D warnings"
BINSTALL_VERSION: "v1.12.3"
BINSTALL_VERSION: "v1.12.5"
concurrency:
group: ${{github.workflow}}-${{github.ref}}
@ -95,7 +95,7 @@ jobs:
- name: CI job
# To run the tests one item at a time for troubleshooting, use
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_ecs --lib -- --exact
run: cargo miri test -p bevy_ecs
run: cargo miri test -p bevy_ecs --features bevy_utils/debug
env:
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
RUSTFLAGS: -Zrandomize-layout
@ -247,7 +247,7 @@ jobs:
- name: Check wasm
run: cargo check --target wasm32-unknown-unknown -Z build-std=std,panic_abort
env:
RUSTFLAGS: "-C target-feature=+atomics,+bulk-memory -D warnings"
RUSTFLAGS: "-C target-feature=+atomics,+bulk-memory"
markdownlint:
runs-on: ubuntu-latest
@ -272,7 +272,7 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: cargo-bins/cargo-binstall@v1.12.3
- uses: cargo-bins/cargo-binstall@v1.12.5
- name: Install taplo
run: cargo binstall taplo-cli@0.9.3 --locked
- name: Run Taplo

View File

@ -49,7 +49,8 @@ jobs:
--exclude ci \
--exclude errors \
--exclude bevy_mobile_example \
--exclude build-wasm-example
--exclude build-wasm-example \
--exclude no_std_library
- name: Create PR
uses: peter-evans/create-pull-request@v7

View File

@ -1,6 +1,6 @@
[package]
name = "bevy"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
categories = ["game-engines", "graphics", "gui", "rendering"]
description = "A refreshingly simple data-driven game engine and app framework"
@ -72,7 +72,6 @@ allow_attributes_without_reason = "warn"
[workspace.lints.rust]
missing_docs = "warn"
mismatched_lifetime_syntaxes = "allow"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] }
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "warn"
@ -134,6 +133,7 @@ default = [
"bevy_audio",
"bevy_color",
"bevy_core_pipeline",
"bevy_core_widgets",
"bevy_anti_aliasing",
"bevy_gilrs",
"bevy_gizmos",
@ -164,6 +164,7 @@ default = [
"vorbis",
"webgl2",
"x11",
"debug",
]
# Recommended defaults for no_std applications
@ -246,6 +247,15 @@ bevy_render = ["bevy_internal/bevy_render", "bevy_color"]
# Provides scene functionality
bevy_scene = ["bevy_internal/bevy_scene", "bevy_asset"]
# Provides raytraced lighting (experimental)
bevy_solari = [
"bevy_internal/bevy_solari",
"bevy_asset",
"bevy_core_pipeline",
"bevy_pbr",
"bevy_render",
]
# Provides sprite functionality
bevy_sprite = [
"bevy_internal/bevy_sprite",
@ -292,6 +302,9 @@ bevy_log = ["bevy_internal/bevy_log"]
# Enable input focus subsystem
bevy_input_focus = ["bevy_internal/bevy_input_focus"]
# Headless widget collection for Bevy UI.
bevy_core_widgets = ["bevy_internal/bevy_core_widgets"]
# Enable passthrough loading for SPIR-V shaders (Only supported on Vulkan, shader capabilities and extensions must agree with the platform implementation)
spirv_shader_passthrough = ["bevy_internal/spirv_shader_passthrough"]
@ -317,6 +330,9 @@ trace = ["bevy_internal/trace", "dep:tracing"]
# Basis Universal compressed texture support
basis-universal = ["bevy_internal/basis-universal"]
# Enables compressed KTX2 UASTC texture output on the asset processor
compressed_image_saver = ["bevy_internal/compressed_image_saver"]
# BMP image format support
bmp = ["bevy_internal/bmp"]
@ -494,7 +510,10 @@ file_watcher = ["bevy_internal/file_watcher"]
embedded_watcher = ["bevy_internal/embedded_watcher"]
# Enable stepping-based debugging of Bevy systems
bevy_debug_stepping = ["bevy_internal/bevy_debug_stepping"]
bevy_debug_stepping = [
"bevy_internal/bevy_debug_stepping",
"bevy_internal/debug",
]
# Enables the meshlet renderer for dense high-poly scenes (experimental)
meshlet = ["bevy_internal/meshlet"]
@ -538,30 +557,33 @@ web = ["bevy_internal/web"]
# Enable hotpatching of Bevy systems
hotpatching = ["bevy_internal/hotpatching"]
# Enable collecting debug information about systems and components to help with diagnostics
debug = ["bevy_internal/debug"]
[dependencies]
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
bevy_internal = { path = "crates/bevy_internal", version = "0.17.0-dev", default-features = false }
tracing = { version = "0.1", default-features = false, optional = true }
# Wasm does not support dynamic linking.
[target.'cfg(not(target_family = "wasm"))'.dependencies]
bevy_dylib = { path = "crates/bevy_dylib", version = "0.16.0-dev", default-features = false, optional = true }
bevy_dylib = { path = "crates/bevy_dylib", version = "0.17.0-dev", default-features = false, optional = true }
[dev-dependencies]
rand = "0.8.0"
rand_chacha = "0.3.1"
ron = "0.8.0"
ron = "0.10"
flate2 = "1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.140"
bytemuck = "1.7"
bevy_render = { path = "crates/bevy_render", version = "0.16.0-dev", default-features = false }
bevy_render = { path = "crates/bevy_render", version = "0.17.0-dev", default-features = false }
# The following explicit dependencies are needed for proc macros to work inside of examples as they are part of the bevy crate itself.
bevy_ecs = { path = "crates/bevy_ecs", version = "0.16.0-dev", default-features = false }
bevy_state = { path = "crates/bevy_state", version = "0.16.0-dev", default-features = false }
bevy_asset = { path = "crates/bevy_asset", version = "0.16.0-dev", default-features = false }
bevy_reflect = { path = "crates/bevy_reflect", version = "0.16.0-dev", default-features = false }
bevy_image = { path = "crates/bevy_image", version = "0.16.0-dev", default-features = false }
bevy_gizmos = { path = "crates/bevy_gizmos", version = "0.16.0-dev", default-features = false }
bevy_ecs = { path = "crates/bevy_ecs", version = "0.17.0-dev", default-features = false }
bevy_state = { path = "crates/bevy_state", version = "0.17.0-dev", default-features = false }
bevy_asset = { path = "crates/bevy_asset", version = "0.17.0-dev", default-features = false }
bevy_reflect = { path = "crates/bevy_reflect", version = "0.17.0-dev", default-features = false }
bevy_image = { path = "crates/bevy_image", version = "0.17.0-dev", default-features = false }
bevy_gizmos = { path = "crates/bevy_gizmos", version = "0.17.0-dev", default-features = false }
# Needed to poll Task examples
futures-lite = "2.0.1"
async-std = "1.13"
@ -588,7 +610,7 @@ web-sys = { version = "0.3", features = ["Window"] }
[[example]]
name = "context_menu"
path = "examples/usages/context_menu.rs"
path = "examples/usage/context_menu.rs"
doc-scrape-examples = true
[package.metadata.example.context_menu]
@ -826,6 +848,17 @@ description = "Generates a texture atlas (sprite sheet) from individual sprites"
category = "2D Rendering"
wasm = false
[[example]]
name = "tilemap_chunk"
path = "examples/2d/tilemap_chunk.rs"
doc-scrape-examples = true
[package.metadata.example.tilemap_chunk]
name = "Tilemap Chunk"
description = "Renders a tilemap chunk"
category = "2D Rendering"
wasm = true
[[example]]
name = "transparency_2d"
path = "examples/2d/transparency_2d.rs"
@ -1257,6 +1290,18 @@ description = "Load a cubemap texture onto a cube like a skybox and cycle throug
category = "3D Rendering"
wasm = false
[[example]]
name = "solari"
path = "examples/3d/solari.rs"
doc-scrape-examples = true
required-features = ["bevy_solari"]
[package.metadata.example.solari]
name = "Solari"
description = "Demonstrates realtime dynamic raytraced lighting using Bevy Solari."
category = "3D Rendering"
wasm = false # Raytracing is not supported on the web
[[example]]
name = "spherical_area_lights"
path = "examples/3d/spherical_area_lights.rs"
@ -2073,6 +2118,7 @@ wasm = false
name = "dynamic"
path = "examples/ecs/dynamic.rs"
doc-scrape-examples = true
required-features = ["debug"]
[package.metadata.example.dynamic]
name = "Dynamic ECS"
@ -4438,3 +4484,25 @@ name = "Hotpatching Systems"
description = "Demonstrates how to hotpatch systems"
category = "ECS (Entity Component System)"
wasm = false
[[example]]
name = "core_widgets"
path = "examples/ui/core_widgets.rs"
doc-scrape-examples = true
[package.metadata.example.core_widgets]
name = "Core Widgets"
description = "Demonstrates use of core (headless) widgets in Bevy UI"
category = "UI (User Interface)"
wasm = true
[[example]]
name = "core_widgets_observers"
path = "examples/ui/core_widgets_observers.rs"
doc-scrape-examples = true
[package.metadata.example.core_widgets_observers]
name = "Core Widgets (w/Observers)"
description = "Demonstrates use of core (headless) widgets in Bevy UI, with Observers"
category = "UI (User Interface)"
wasm = true

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="svg2321"
version="1.1"
viewBox="0 0 63.304429 63.304432"
height="63.304432mm"
width="63.304428mm"
sodipodi:docname="bevy_solari.svg"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.27643554"
inkscape:cx="54.262198"
inkscape:cy="-311.10327"
inkscape:window-width="1440"
inkscape:window-height="788"
inkscape:window-x="-6"
inkscape:window-y="-6"
inkscape:window-maximized="1"
inkscape:current-layer="svg2321" />
<defs
id="defs2315" />
<metadata
id="metadata2318">
<rdf:RDF>
<cc:Work
rdf:about="" />
</rdf:RDF>
</metadata>
<g
id="g11"
style="display:inline"
transform="translate(-27.298342,-111.49082)">
<path
style="fill:#ff8904;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-opacity:1"
id="path10-7"
d="m 38.15031,109.44704 c 0.743942,3.07133 6.496307,7.00051 6.678099,10.15542 0.116231,2.01713 -5.225098,3.23914 -5.79502,5.17757 -0.891392,3.03182 2.125712,9.31077 0.705692,12.1339 -0.907907,1.80501 -6.144635,0.19263 -7.607418,1.5864 -2.287879,2.17994 -2.814466,9.12622 -5.455804,10.86111 -1.688772,1.10923 -5.417723,-2.9055 -7.381414,-2.42985 -3.071331,0.74394 -7.000511,6.49631 -10.1554234,6.6781 -2.0171309,0.11623 -3.2391354,-5.2251 -5.1775665,-5.79502 -3.03182154,-0.89139 -9.3107731,2.12571 -12.1339038,0.70569 -1.8050021,-0.9079 -0.1926248,-6.14463 -1.5863942,-7.60742 -2.1799381,-2.28787 -9.1262221,-2.81446 -10.8611151,-5.4558 -1.109224,-1.68877 2.9055,-5.41772 2.429851,-7.38141 -0.743942,-3.07133 -6.496306,-7.00051 -6.678099,-10.15543 -0.116231,-2.01713 5.225098,-3.23913 5.79502,-5.17756 0.891393,-3.03182 -2.125711,-9.31078 -0.705692,-12.13391 0.907907,-1.804999 6.144635,-0.19262 7.607418,-1.586391 2.2878791,-2.179939 2.8144662,-9.126222 5.4558046,-10.861115 1.6887711,-1.109225 5.4177222,2.905499 7.38141398,2.429851 3.07133072,-0.743942 7.00051032,-6.496307 10.15542342,-6.678099 2.01713,-0.116231 3.239135,5.225097 5.177566,5.79502 3.031822,0.891392 9.310773,-2.125712 12.133904,-0.705692 1.805002,0.907906 0.192625,6.144634 1.586394,7.607417 2.179938,2.28788 9.126222,2.814467 10.861115,5.455809 1.109224,1.68877 -2.905499,5.41772 -2.429851,7.38141 z"
transform="matrix(0.90823691,0,0,0.90823691,49.886257,35.27956)" />
<g
id="g3-6"
transform="translate(-517.96199,-278.01119)"
style="display:inline;opacity:1;fill:#ffd230;fill-opacity:1;stroke-width:0.755906;stroke-miterlimit:4;stroke-dasharray:none">
<g
transform="matrix(-0.40426719,-0.17438247,-0.17438247,0.40426719,678.77611,389.84765)"
style="fill:#ffd230;fill-opacity:1"
id="g2-1">
<path
id="path1-4"
style="fill:#ffd230;fill-opacity:1;stroke:none;stroke-width:0.559814px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 2246.0312,2340.1914 v 0 c -0.016,3e-4 -0.031,0 -0.047,0 -0.9804,3.0675 -1.7386,6.3997 -1.8828,10.1953 -0.2712,7.1263 0.453,11.4639 -0.3672,16.0801 -0.8202,4.6163 -3.2453,9.161 -9.4141,16.2871 -7.3424,8.482 -18.9789,15.0453 -32.4199,17.2637 -2.5015,1.5971 -5.1421,3.0609 -7.9199,4.3633 10.4618,3.9385 21.4025,4.1531 30.0761,1.3066 15.2793,-5.0141 14.0962,-8.6155 20.9434,-19.1074 2.1569,-3.3051 4.6474,-5.8282 7.1484,-7.9004 7.1248,3.1068 14.1431,5.1015 18.5157,4.6074 2.351,-5.4505 -0.057,-11.7712 -4.0586,-17.7461 3.2821,-10.196 -1.6986,-20.4059 -12.7305,-24.0156 -2.8775,-0.9415 -5.4633,-1.3844 -7.8438,-1.3379 z m 8.2754,14.9707 a 4.1668789,4.2454995 48.679502 0 1 3.1973,1.3965 4.1668789,4.2454995 48.679502 0 1 -0.4375,5.9336 4.1668789,4.2454995 48.679502 0 1 -5.9394,-0.3262 4.1668789,4.2454995 48.679502 0 1 0.4375,-5.9336 4.1668789,4.2454995 48.679502 0 1 2.7421,-1.0703 z m -68.375,45.3789 c 0.1273,0.075 0.2572,0.1408 0.3848,0.2149 0.131,-0.049 0.2642,-0.1009 0.3945,-0.1504 -0.2598,-0.023 -0.5188,-0.039 -0.7793,-0.064 z"
transform="matrix(-0.55180403,-0.23802315,-0.23802315,0.55180403,1946.7322,-620.612)" />
</g>
</g>
<g
id="g5-2"
transform="matrix(-0.45399624,0.36689705,0.36689705,0.45399624,73.527335,10.816805)"
style="display:inline;opacity:1;fill:#fef3c6;fill-opacity:1;stroke:none;stroke-width:0.755906;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<g
id="g4-3"
transform="matrix(-0.35254083,0.28490586,0.28490586,0.35254083,477.11004,-1021.7666)"
style="opacity:1;fill:#fef3c6;fill-opacity:1">
<path
id="path2-2"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fef3c6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.02362;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m 2191.1465,2276.7832 c -5.9729,-0.035 -12.0979,2.348 -17.3613,7.459 -6.9129,6.7127 -9.0602,12.7555 -7.8477,20.2949 l 0.332,2.0684 -2.0664,-0.336 c -15.1877,-2.4609 -33.9847,-1.2178 -55.3711,7.4336 6.2868,2.6948 17.8259,7.1926 30.6309,13.3418 l 4.0605,1.9512 -4.414,0.8945 c -16.9087,3.4274 -36.9729,13.3275 -55.2989,34.9336 8.1981,-0.6372 24.9531,-2.6089 42.4278,-2.582 9.7138,0.015 19.2869,0.687 27.0859,2.709 7.7991,2.022 14.8874,6.6498 15.8861,10.0406 0.9987,3.3908 0.432,5.1761 -0.5519,7.8285 -0.9839,2.6524 -4.0098,6.6817 -8.1953,9.3418 -4.1855,2.6601 -9.4961,4.9849 -15.0137,6.9609 -11.0352,3.9521 -22.7798,6.4773 -27.9648,6.959 -1.1021,0.1024 -1.5421,0.4983 -1.9668,1.2696 -0.4247,0.7712 -0.659,1.9824 -0.6934,3.25 -0.046,1.6926 0.217,2.576 0.6949,3.246 0.4779,0.67 1.2243,0.9381 1.9934,0.9902 32.5822,2.2052 56.9441,-5.9907 74.6379,-13.0116 20.3508,-9.3311 33.2134,-27.7577 36.0058,-44.3477 1.7499,-10.395 1.3746,-15.4894 -0.3124,-19.8281 -1.6873,-4.3387 -4.9223,-8.1914 -9.0254,-15.5488 -2.6368,-4.7281 -4.1077,-9.367 -5.0196,-13.6875 l -0.1933,-0.9102 0.7265,-0.582 c 7.5403,-6.0446 13.6809,-12.6444 15.9102,-17.4492 -4.5742,-4.8648 -12.4787,-5.893 -21.3223,-4.9473 l -0.7265,0.076 -0.5118,-0.5215 c -4.7125,-4.8006 -10.5615,-7.2614 -16.5351,-7.2969 z m 2.6484,11.2324 c 2.593,-0.041 4.8808,1.7566 5.502,4.3223 0.7307,3.0216 -1.0812,6.0525 -4.0469,6.7695 -2.9656,0.7176 -5.9625,-1.1502 -6.6934,-4.1719 -0.7307,-3.0216 1.0812,-6.0525 4.0469,-6.7695 0.3902,-0.094 0.7897,-0.1445 1.1914,-0.1504 z"
transform="translate(5.0092774e-5,-757.87625)" />
</g>
</g>
<g
style="display:inline;opacity:1;fill:#fee685;fill-opacity:1;stroke-width:0.755906;stroke-miterlimit:4;stroke-dasharray:none"
id="g10-2"
transform="matrix(-0.50509374,0.06754889,0.06754889,0.50509374,156.75523,55.243465)">
<g
style="fill:#fee685;fill-opacity:1"
id="g9-1"
transform="translate(-20.244579,-6.1209206)">
<g
style="fill:#fee685;fill-opacity:1"
id="g8-6"
transform="translate(61.54776,-5.6726683)">
<g
id="g7-8"
style="fill:#fee685;fill-opacity:1">
<g
id="g6-5"
transform="matrix(-0.514626,0.06882369,0.06882369,0.514626,1184.3644,-811.9091)"
style="opacity:1;fill:#fee685;fill-opacity:1">
<path
id="path4-7"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fee685;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.02362;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m 2230.8945,2301.1738 c -1.9108,-0.039 -3.9117,0.162 -5.9785,0.6328 -0.1394,0.032 -0.2613,0.071 -0.3984,0.1036 -2.274,2.2481 -4.8127,4.5047 -7.5293,6.7168 0.8746,3.8597 2.1735,7.8829 4.4707,12.0019 3.9872,7.1495 7.2742,10.9657 9.2031,15.9258 1.9289,4.9601 2.2639,10.7945 0.4746,21.4238 -2.2183,13.178 -10.2404,27.1324 -22.959,37.4336 9.8717,-2.8792 18.2866,-8.1915 23.8575,-14.6269 6.0132,-6.9464 8.0191,-10.8762 8.7226,-14.836 0.7036,-3.9598 0.044,-8.2997 0.3242,-15.664 0.1805,-4.7447 1.1911,-8.8958 2.4766,-12.545 l 0.3086,-0.875 0.9219,-0.1211 c 8.2284,-1.0673 15.6654,-3.167 19.5097,-5.6484 -1.2349,-5.5522 -6.4807,-9.8603 -13.4277,-13.1348 l -0.6621,-0.3125 -0.166,-0.7129 c -2.2034,-9.4614 -9.5905,-15.5632 -19.1485,-15.7617 z m 4.7832,11.6856 a 4.8229105,4.9139092 17.729059 0 1 1.4473,0.2246 4.8229105,4.9139092 17.729059 0 1 3.0977,6.1484 4.8229105,4.9139092 17.729059 0 1 -6.0899,3.2129 4.8229105,4.9139092 17.729059 0 1 -3.0976,-6.1484 4.8229105,4.9139092 17.729059 0 1 4.6425,-3.4375 z"
transform="translate(1.2499985e-4,-757.87627)" />
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -7,8 +7,8 @@
}
#import bevy_core_pipeline::tonemapping::tone_mapping
@group(2) @binding(0) var my_array_texture: texture_2d_array<f32>;
@group(2) @binding(1) var my_array_texture_sampler: sampler;
@group(3) @binding(0) var my_array_texture: texture_2d_array<f32>;
@group(3) @binding(1) var my_array_texture_sampler: sampler;
@fragment
fn fragment(

View File

@ -3,8 +3,8 @@
view_transformations::position_world_to_clip
}
@group(2) @binding(0) var texture: texture_2d<f32>;
@group(2) @binding(1) var texture_sampler: sampler;
@group(3) @binding(0) var texture: texture_2d<f32>;
@group(3) @binding(1) var texture_sampler: sampler;
struct Vertex {
@builtin(instance_index) instance_index: u32,

View File

@ -15,12 +15,12 @@ struct MaterialBindings {
}
#ifdef BINDLESS
@group(2) @binding(0) var<storage> materials: array<MaterialBindings>;
@group(2) @binding(10) var<storage> material_color: binding_array<Color>;
@group(3) @binding(0) var<storage> materials: array<MaterialBindings>;
@group(3) @binding(10) var<storage> material_color: binding_array<Color>;
#else // BINDLESS
@group(2) @binding(0) var<uniform> material_color: Color;
@group(2) @binding(1) var material_color_texture: texture_2d<f32>;
@group(2) @binding(2) var material_color_sampler: sampler;
@group(3) @binding(0) var<uniform> material_color: Color;
@group(3) @binding(1) var material_color_texture: texture_2d<f32>;
@group(3) @binding(2) var material_color_sampler: sampler;
#endif // BINDLESS
@fragment

View File

@ -1,12 +1,12 @@
#import bevy_pbr::forward_io::VertexOutput
#ifdef CUBEMAP_ARRAY
@group(2) @binding(0) var base_color_texture: texture_cube_array<f32>;
@group(3) @binding(0) var base_color_texture: texture_cube_array<f32>;
#else
@group(2) @binding(0) var base_color_texture: texture_cube<f32>;
@group(3) @binding(0) var base_color_texture: texture_cube<f32>;
#endif
@group(2) @binding(1) var base_color_sampler: sampler;
@group(3) @binding(1) var base_color_sampler: sampler;
@fragment
fn fragment(

View File

@ -3,10 +3,10 @@ layout(location = 0) in vec2 v_Uv;
layout(location = 0) out vec4 o_Target;
layout(set = 2, binding = 0) uniform vec4 CustomMaterial_color;
layout(set = 3, binding = 0) uniform vec4 CustomMaterial_color;
layout(set = 2, binding = 1) uniform texture2D CustomMaterial_texture;
layout(set = 2, binding = 2) uniform sampler CustomMaterial_sampler;
layout(set = 3, binding = 1) uniform texture2D CustomMaterial_texture;
layout(set = 3, binding = 2) uniform sampler CustomMaterial_sampler;
// wgsl modules can be imported and used in glsl
// FIXME - this doesn't work any more ...

View File

@ -25,9 +25,9 @@ struct Mesh {
};
#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
layout(set = 1, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
layout(set = 2, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
#else
layout(set = 1, binding = 0) readonly buffer _Meshes {
layout(set = 2, binding = 0) readonly buffer _Meshes {
Mesh Meshes[];
};
#endif // PER_OBJECT_BUFFER_BATCH_SIZE

View File

@ -10,7 +10,7 @@ struct CustomMaterial {
time: vec4<f32>,
}
@group(2) @binding(0) var<uniform> material: CustomMaterial;
@group(3) @binding(0) var<uniform> material: CustomMaterial;
@fragment
fn fragment(

View File

@ -2,9 +2,9 @@
// we can import items from shader modules in the assets folder with a quoted path
#import "shaders/custom_material_import.wgsl"::COLOR_MULTIPLIER
@group(2) @binding(0) var<uniform> material_color: vec4<f32>;
@group(2) @binding(1) var material_color_texture: texture_2d<f32>;
@group(2) @binding(2) var material_color_sampler: sampler;
@group(3) @binding(0) var<uniform> material_color: vec4<f32>;
@group(3) @binding(1) var material_color_texture: texture_2d<f32>;
@group(3) @binding(2) var material_color_sampler: sampler;
@fragment
fn fragment(

View File

@ -4,8 +4,8 @@
utils::coords_to_viewport_uv,
}
@group(2) @binding(0) var texture: texture_2d<f32>;
@group(2) @binding(1) var texture_sampler: sampler;
@group(3) @binding(0) var texture: texture_2d<f32>;
@group(3) @binding(1) var texture_sampler: sampler;
@fragment
fn fragment(

View File

@ -3,7 +3,7 @@
struct CustomMaterial {
color: vec4<f32>,
};
@group(2) @binding(0) var<uniform> material: CustomMaterial;
@group(3) @binding(0) var<uniform> material: CustomMaterial;
struct Vertex {
@builtin(instance_index) instance_index: u32,

View File

@ -19,7 +19,7 @@ struct MyExtendedMaterial {
quantize_steps: u32,
}
@group(2) @binding(100)
@group(3) @binding(100)
var<uniform> my_extended_material: MyExtendedMaterial;
@fragment

View File

@ -42,19 +42,19 @@ struct ExampleBindlessExtendedMaterial {
// The indices of the bindless resources in the bindless resource arrays, for
// the `ExampleBindlessExtension` fields.
@group(2) @binding(100) var<storage> example_extended_material_indices:
@group(3) @binding(100) var<storage> example_extended_material_indices:
array<ExampleBindlessExtendedMaterialIndices>;
// An array that holds the `ExampleBindlessExtendedMaterial` plain old data,
// indexed by `ExampleBindlessExtendedMaterialIndices.material`.
@group(2) @binding(101) var<storage> example_extended_material:
@group(3) @binding(101) var<storage> example_extended_material:
array<ExampleBindlessExtendedMaterial>;
#else // BINDLESS
// In non-bindless mode, we simply use a uniform for the plain old data.
@group(2) @binding(50) var<uniform> example_extended_material: ExampleBindlessExtendedMaterial;
@group(2) @binding(51) var modulate_texture: texture_2d<f32>;
@group(2) @binding(52) var modulate_sampler: sampler;
@group(3) @binding(50) var<uniform> example_extended_material: ExampleBindlessExtendedMaterial;
@group(3) @binding(51) var modulate_texture: texture_2d<f32>;
@group(3) @binding(52) var modulate_sampler: sampler;
#endif // BINDLESS

View File

@ -1,22 +1,22 @@
#import bevy_pbr::forward_io::VertexOutput
@group(2) @binding(0) var test_texture_1d: texture_1d<f32>;
@group(2) @binding(1) var test_texture_1d_sampler: sampler;
@group(3) @binding(0) var test_texture_1d: texture_1d<f32>;
@group(3) @binding(1) var test_texture_1d_sampler: sampler;
@group(2) @binding(2) var test_texture_2d: texture_2d<f32>;
@group(2) @binding(3) var test_texture_2d_sampler: sampler;
@group(3) @binding(2) var test_texture_2d: texture_2d<f32>;
@group(3) @binding(3) var test_texture_2d_sampler: sampler;
@group(2) @binding(4) var test_texture_2d_array: texture_2d_array<f32>;
@group(2) @binding(5) var test_texture_2d_array_sampler: sampler;
@group(3) @binding(4) var test_texture_2d_array: texture_2d_array<f32>;
@group(3) @binding(5) var test_texture_2d_array_sampler: sampler;
@group(2) @binding(6) var test_texture_cube: texture_cube<f32>;
@group(2) @binding(7) var test_texture_cube_sampler: sampler;
@group(3) @binding(6) var test_texture_cube: texture_cube<f32>;
@group(3) @binding(7) var test_texture_cube_sampler: sampler;
@group(2) @binding(8) var test_texture_cube_array: texture_cube_array<f32>;
@group(2) @binding(9) var test_texture_cube_array_sampler: sampler;
@group(3) @binding(8) var test_texture_cube_array: texture_cube_array<f32>;
@group(3) @binding(9) var test_texture_cube_array_sampler: sampler;
@group(2) @binding(10) var test_texture_3d: texture_3d<f32>;
@group(2) @binding(11) var test_texture_3d_sampler: sampler;
@group(3) @binding(10) var test_texture_3d: texture_3d<f32>;
@group(3) @binding(11) var test_texture_3d_sampler: sampler;
@fragment
fn fragment(in: VertexOutput) {}

View File

@ -12,7 +12,7 @@ struct VoxelVisualizationIrradianceVolumeInfo {
intensity: f32,
}
@group(2) @binding(100)
@group(3) @binding(100)
var<uniform> irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo;
@fragment

View File

@ -4,7 +4,7 @@ struct LineMaterial {
color: vec4<f32>,
};
@group(2) @binding(0) var<uniform> material: LineMaterial;
@group(3) @binding(0) var<uniform> material: LineMaterial;
@fragment
fn fragment(

View File

@ -4,7 +4,7 @@ struct CustomMaterial {
color: vec4<f32>,
};
@group(2) @binding(0) var<uniform> material: CustomMaterial;
@group(3) @binding(0) var<uniform> material: CustomMaterial;
@fragment
fn fragment(

View File

@ -11,7 +11,7 @@ struct ShowPrepassSettings {
padding_1: u32,
padding_2: u32,
}
@group(2) @binding(0) var<uniform> settings: ShowPrepassSettings;
@group(3) @binding(0) var<uniform> settings: ShowPrepassSettings;
@fragment
fn fragment(

View File

@ -3,7 +3,7 @@
view_transformations::position_world_to_clip
}
@group(2) @binding(0) var<storage, read> colors: array<vec4<f32>, 5>;
@group(3) @binding(0) var<storage, read> colors: array<vec4<f32>, 5>;
struct Vertex {
@builtin(instance_index) instance_index: u32,

View File

@ -1,7 +1,7 @@
#import bevy_pbr::forward_io::VertexOutput
@group(2) @binding(0) var textures: binding_array<texture_2d<f32>>;
@group(2) @binding(1) var nearest_sampler: sampler;
@group(3) @binding(0) var textures: binding_array<texture_2d<f32>>;
@group(3) @binding(1) var nearest_sampler: sampler;
// We can also have array of samplers
// var samplers: binding_array<sampler>;

View File

@ -23,9 +23,9 @@ struct WaterSettings {
@group(0) @binding(1) var<uniform> globals: Globals;
@group(2) @binding(100) var water_normals_texture: texture_2d<f32>;
@group(2) @binding(101) var water_normals_sampler: sampler;
@group(2) @binding(102) var<uniform> water_settings: WaterSettings;
@group(3) @binding(100) var water_normals_texture: texture_2d<f32>;
@group(3) @binding(101) var water_normals_sampler: sampler;
@group(3) @binding(102) var<uniform> water_settings: WaterSettings;
// Samples a single octave of noise and returns the resulting normal.
fn sample_noise_octave(uv: vec2<f32>, strength: f32) -> vec3<f32> {

View File

@ -49,6 +49,7 @@ impl BenchModify for Table {
black_box(self.0)
}
}
impl BenchModify for Sparse {
fn bench_modify(&mut self) -> f32 {
self.0 += 1f32;

View File

@ -1,7 +1,7 @@
use core::hint::black_box;
use benches::bench;
use bevy_ecs::bundle::Bundle;
use bevy_ecs::bundle::{Bundle, InsertMode};
use bevy_ecs::component::ComponentCloneBehavior;
use bevy_ecs::entity::EntityCloner;
use bevy_ecs::hierarchy::ChildOf;
@ -17,41 +17,15 @@ criterion_group!(
hierarchy_tall,
hierarchy_wide,
hierarchy_many,
filter
);
#[derive(Component, Reflect, Default, Clone)]
struct C1(Mat4);
struct C<const N: usize>(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C2(Mat4);
type ComplexBundle = (C<1>, C<2>, C<3>, C<4>, C<5>, C<6>, C<7>, C<8>, C<9>, C<10>);
#[derive(Component, Reflect, Default, Clone)]
struct C3(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C4(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C5(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C6(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C7(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C8(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C9(Mat4);
#[derive(Component, Reflect, Default, Clone)]
struct C10(Mat4);
type ComplexBundle = (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10);
/// Sets the [`ComponentCloneHandler`] for all explicit and required components in a bundle `B` to
/// Sets the [`ComponentCloneBehavior`] for all explicit and required components in a bundle `B` to
/// use the [`Reflect`] trait instead of [`Clone`].
fn reflection_cloner<B: Bundle + GetTypeRegistration>(
world: &mut World,
@ -71,7 +45,7 @@ fn reflection_cloner<B: Bundle + GetTypeRegistration>(
// this bundle are saved.
let component_ids: Vec<_> = world.register_bundle::<B>().contributed_components().into();
let mut builder = EntityCloner::build(world);
let mut builder = EntityCloner::build_opt_out(world);
// Overwrite the clone handler for all components in the bundle to use `Reflect`, not `Clone`.
for component in component_ids {
@ -82,16 +56,15 @@ fn reflection_cloner<B: Bundle + GetTypeRegistration>(
builder.finish()
}
/// A helper function that benchmarks running the [`EntityCommands::clone_and_spawn()`] command on a
/// bundle `B`.
/// A helper function that benchmarks running [`EntityCloner::spawn_clone`] with a bundle `B`.
///
/// The bundle must implement [`Default`], which is used to create the first entity that gets cloned
/// in the benchmark.
///
/// If `clone_via_reflect` is false, this will use the default [`ComponentCloneHandler`] for all
/// components (which is usually [`ComponentCloneHandler::clone_handler()`]). If `clone_via_reflect`
/// If `clone_via_reflect` is false, this will use the default [`ComponentCloneBehavior`] for all
/// components (which is usually [`ComponentCloneBehavior::clone()`]). If `clone_via_reflect`
/// is true, it will overwrite the handler for all components in the bundle to be
/// [`ComponentCloneHandler::reflect_handler()`].
/// [`ComponentCloneBehavior::reflect()`].
fn bench_clone<B: Bundle + Default + GetTypeRegistration>(
b: &mut Bencher,
clone_via_reflect: bool,
@ -114,8 +87,7 @@ fn bench_clone<B: Bundle + Default + GetTypeRegistration>(
});
}
/// A helper function that benchmarks running the [`EntityCommands::clone_and_spawn()`] command on a
/// bundle `B`.
/// A helper function that benchmarks running [`EntityCloner::spawn_clone`] with a bundle `B`.
///
/// As compared to [`bench_clone()`], this benchmarks recursively cloning an entity with several
/// children. It does so by setting up an entity tree with a given `height` where each entity has a
@ -135,7 +107,7 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
let mut cloner = if clone_via_reflect {
reflection_cloner::<B>(&mut world, true)
} else {
let mut builder = EntityCloner::build(&mut world);
let mut builder = EntityCloner::build_opt_out(&mut world);
builder.linked_cloning(true);
builder.finish()
};
@ -169,7 +141,7 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
// Each benchmark runs twice: using either the `Clone` or `Reflect` traits to clone entities. This
// constant represents this as an easy array that can be used in a `for` loop.
const SCENARIOS: [(&str, bool); 2] = [("clone", false), ("reflect", true)];
const CLONE_SCENARIOS: [(&str, bool); 2] = [("clone", false), ("reflect", true)];
/// Benchmarks cloning a single entity with 10 components and no children.
fn single(c: &mut Criterion) {
@ -178,7 +150,7 @@ fn single(c: &mut Criterion) {
// We're cloning 1 entity.
group.throughput(Throughput::Elements(1));
for (id, clone_via_reflect) in SCENARIOS {
for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone::<ComplexBundle>(b, clone_via_reflect);
});
@ -194,9 +166,9 @@ fn hierarchy_tall(c: &mut Criterion) {
// We're cloning both the root entity and its 50 descendents.
group.throughput(Throughput::Elements(51));
for (id, clone_via_reflect) in SCENARIOS {
for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone_hierarchy::<C1>(b, 50, 1, clone_via_reflect);
bench_clone_hierarchy::<C<1>>(b, 50, 1, clone_via_reflect);
});
}
@ -210,9 +182,9 @@ fn hierarchy_wide(c: &mut Criterion) {
// We're cloning both the root entity and its 50 direct children.
group.throughput(Throughput::Elements(51));
for (id, clone_via_reflect) in SCENARIOS {
for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone_hierarchy::<C1>(b, 1, 50, clone_via_reflect);
bench_clone_hierarchy::<C<1>>(b, 1, 50, clone_via_reflect);
});
}
@ -228,7 +200,7 @@ fn hierarchy_many(c: &mut Criterion) {
// of entities spawned in `bench_clone_hierarchy()` with a `println!()` statement. :)
group.throughput(Throughput::Elements(364));
for (id, clone_via_reflect) in SCENARIOS {
for (id, clone_via_reflect) in CLONE_SCENARIOS {
group.bench_function(id, |b| {
bench_clone_hierarchy::<ComplexBundle>(b, 5, 3, clone_via_reflect);
});
@ -236,3 +208,157 @@ fn hierarchy_many(c: &mut Criterion) {
group.finish();
}
/// Filter scenario variant for bot opt-in and opt-out filters
#[derive(Clone, Copy)]
#[expect(
clippy::enum_variant_names,
reason = "'Opt' is not understood as an prefix but `OptOut'/'OptIn' are"
)]
enum FilterScenario {
OptOutNone,
OptOutNoneKeep(bool),
OptOutAll,
OptInNone,
OptInAll,
OptInAllWithoutRequired,
OptInAllKeep(bool),
OptInAllKeepWithoutRequired(bool),
}
impl From<FilterScenario> for String {
fn from(value: FilterScenario) -> Self {
match value {
FilterScenario::OptOutNone => "opt_out_none",
FilterScenario::OptOutNoneKeep(true) => "opt_out_none_keep_none",
FilterScenario::OptOutNoneKeep(false) => "opt_out_none_keep_all",
FilterScenario::OptOutAll => "opt_out_all",
FilterScenario::OptInNone => "opt_in_none",
FilterScenario::OptInAll => "opt_in_all",
FilterScenario::OptInAllWithoutRequired => "opt_in_all_without_required",
FilterScenario::OptInAllKeep(true) => "opt_in_all_keep_none",
FilterScenario::OptInAllKeep(false) => "opt_in_all_keep_all",
FilterScenario::OptInAllKeepWithoutRequired(true) => {
"opt_in_all_keep_none_without_required"
}
FilterScenario::OptInAllKeepWithoutRequired(false) => {
"opt_in_all_keep_all_without_required"
}
}
.into()
}
}
/// Common scenarios for different filter to be benchmarked.
const FILTER_SCENARIOS: [FilterScenario; 11] = [
FilterScenario::OptOutNone,
FilterScenario::OptOutNoneKeep(true),
FilterScenario::OptOutNoneKeep(false),
FilterScenario::OptOutAll,
FilterScenario::OptInNone,
FilterScenario::OptInAll,
FilterScenario::OptInAllWithoutRequired,
FilterScenario::OptInAllKeep(true),
FilterScenario::OptInAllKeep(false),
FilterScenario::OptInAllKeepWithoutRequired(true),
FilterScenario::OptInAllKeepWithoutRequired(false),
];
/// A helper function that benchmarks running [`EntityCloner::clone_entity`] with a bundle `B`.
///
/// The bundle must implement [`Default`], which is used to create the first entity that gets its components cloned
/// in the benchmark. It may also be used to populate the target entity depending on the scenario.
fn bench_filter<B: Bundle + Default>(b: &mut Bencher, scenario: FilterScenario) {
let mut world = World::default();
let mut spawn = |empty| match empty {
false => world.spawn(B::default()).id(),
true => world.spawn_empty().id(),
};
let source = spawn(false);
let (target, mut cloner);
match scenario {
FilterScenario::OptOutNone => {
target = spawn(true);
cloner = EntityCloner::default();
}
FilterScenario::OptOutNoneKeep(is_new) => {
target = spawn(is_new);
let mut builder = EntityCloner::build_opt_out(&mut world);
builder.insert_mode(InsertMode::Keep);
cloner = builder.finish();
}
FilterScenario::OptOutAll => {
target = spawn(true);
let mut builder = EntityCloner::build_opt_out(&mut world);
builder.deny::<B>();
cloner = builder.finish();
}
FilterScenario::OptInNone => {
target = spawn(true);
let builder = EntityCloner::build_opt_in(&mut world);
cloner = builder.finish();
}
FilterScenario::OptInAll => {
target = spawn(true);
let mut builder = EntityCloner::build_opt_in(&mut world);
builder.allow::<B>();
cloner = builder.finish();
}
FilterScenario::OptInAllWithoutRequired => {
target = spawn(true);
let mut builder = EntityCloner::build_opt_in(&mut world);
builder.without_required_components(|builder| {
builder.allow::<B>();
});
cloner = builder.finish();
}
FilterScenario::OptInAllKeep(is_new) => {
target = spawn(is_new);
let mut builder = EntityCloner::build_opt_in(&mut world);
builder.allow_if_new::<B>();
cloner = builder.finish();
}
FilterScenario::OptInAllKeepWithoutRequired(is_new) => {
target = spawn(is_new);
let mut builder = EntityCloner::build_opt_in(&mut world);
builder.without_required_components(|builder| {
builder.allow_if_new::<B>();
});
cloner = builder.finish();
}
}
b.iter(|| {
// clones the given entity into the target
cloner.clone_entity(&mut world, black_box(source), black_box(target));
world.flush();
});
}
/// Benchmarks filtering of cloning a single entity with 5 unclonable components (each requiring 1 unclonable component) into a target.
fn filter(c: &mut Criterion) {
#[derive(Component, Default)]
#[component(clone_behavior = Ignore)]
struct C<const N: usize>;
#[derive(Component, Default)]
#[component(clone_behavior = Ignore)]
#[require(C::<N>)]
struct R<const N: usize>;
type RequiringBundle = (R<1>, R<2>, R<3>, R<4>, R<5>);
let mut group = c.benchmark_group(bench!("filter"));
// We're cloning 1 entity into a target.
group.throughput(Throughput::Elements(1));
for scenario in FILTER_SCENARIOS {
group.bench_function(scenario, |b| {
bench_filter::<RequiringBundle>(b, scenario);
});
}
group.finish();
}

View File

@ -1,6 +1,6 @@
use bevy_ecs::prelude::*;
#[derive(Event)]
#[derive(Event, BufferedEvent)]
struct BenchEvent<const SIZE: usize>([u8; SIZE]);
pub struct Benchmark<const SIZE: usize>(Events<BenchEvent<SIZE>>);

View File

@ -10,19 +10,19 @@ fn send(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_4_events_{}", count), |b| {
group.bench_function(format!("size_4_events_{count}"), |b| {
let mut bench = send::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_16_events_{}", count), |b| {
group.bench_function(format!("size_16_events_{count}"), |b| {
let mut bench = send::Benchmark::<16>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_512_events_{}", count), |b| {
group.bench_function(format!("size_512_events_{count}"), |b| {
let mut bench = send::Benchmark::<512>::new(count);
b.iter(move || bench.run());
});
@ -35,19 +35,19 @@ fn iter(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_4_events_{}", count), |b| {
group.bench_function(format!("size_4_events_{count}"), |b| {
let mut bench = iter::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_16_events_{}", count), |b| {
group.bench_function(format!("size_16_events_{count}"), |b| {
let mut bench = iter::Benchmark::<4>::new(count);
b.iter(move || bench.run());
});
}
for count in [100, 1_000, 10_000] {
group.bench_function(format!("size_512_events_{}", count), |b| {
group.bench_function(format!("size_512_events_{count}"), |b| {
let mut bench = iter::Benchmark::<512>::new(count);
b.iter(move || bench.run());
});

View File

@ -1,6 +1,6 @@
use bevy_ecs::prelude::*;
#[derive(Event)]
#[derive(Event, BufferedEvent)]
struct BenchEvent<const SIZE: usize>([u8; SIZE]);
impl<const SIZE: usize> Default for BenchEvent<SIZE> {

View File

@ -130,7 +130,7 @@ fn par_iter_simple(c: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(4));
for f in [0, 10, 100, 1000] {
group.bench_function(format!("with_{}_fragment", f), |b| {
group.bench_function(format!("with_{f}_fragment"), |b| {
let mut bench = par_iter_simple::Benchmark::new(f);
b.iter(move || bench.run());
});

View File

@ -61,14 +61,10 @@ pub fn event_propagation(criterion: &mut Criterion) {
group.finish();
}
#[derive(Clone, Component)]
#[derive(Event, EntityEvent, Clone, Component)]
#[entity_event(traversal = &'static ChildOf, auto_propagate)]
struct TestEvent<const N: usize> {}
impl<const N: usize> Event for TestEvent<N> {
type Traversal = &'static ChildOf;
const AUTO_PROPAGATE: bool = true;
}
fn send_events<const N: usize, const N_EVENTS: usize>(world: &mut World, leaves: &[Entity]) {
let target = leaves.iter().choose(&mut rand::thread_rng()).unwrap();
@ -117,6 +113,6 @@ fn add_listeners_to_hierarchy<const DENSITY: usize, const N: usize>(
}
}
fn empty_listener<const N: usize>(trigger: Trigger<TestEvent<N>>) {
fn empty_listener<const N: usize>(trigger: On<TestEvent<N>>) {
black_box(trigger);
}

View File

@ -1,8 +1,8 @@
use core::hint::black_box;
use bevy_ecs::{
event::Event,
observer::{Trigger, TriggerTargets},
event::{EntityEvent, Event},
observer::{On, TriggerTargets},
world::World,
};
@ -13,7 +13,7 @@ fn deterministic_rand() -> ChaCha8Rng {
ChaCha8Rng::seed_from_u64(42)
}
#[derive(Clone, Event)]
#[derive(Clone, Event, EntityEvent)]
struct EventBase;
pub fn observe_simple(criterion: &mut Criterion) {
@ -46,7 +46,7 @@ pub fn observe_simple(criterion: &mut Criterion) {
group.finish();
}
fn empty_listener_base(trigger: Trigger<EventBase>) {
fn empty_listener_base(trigger: On<EventBase>) {
black_box(trigger);
}

View File

@ -24,7 +24,7 @@ pub fn run_condition_yes(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@ -46,7 +46,7 @@ pub fn run_condition_no(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@ -77,7 +77,7 @@ pub fn run_condition_yes_with_query(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@ -105,7 +105,7 @@ pub fn run_condition_yes_with_resource(criterion: &mut Criterion) {
}
// run once to initialize systems
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});

View File

@ -26,7 +26,7 @@ pub fn empty_systems(criterion: &mut Criterion) {
schedule.add_systems(empty);
}
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@ -38,7 +38,7 @@ pub fn empty_systems(criterion: &mut Criterion) {
schedule.add_systems((empty, empty, empty, empty, empty));
}
schedule.run(&mut world);
group.bench_function(format!("{}_systems", amount), |bencher| {
group.bench_function(format!("{amount}_systems"), |bencher| {
bencher.iter(|| {
schedule.run(&mut world);
});
@ -79,10 +79,7 @@ pub fn busy_systems(criterion: &mut Criterion) {
}
schedule.run(&mut world);
group.bench_function(
format!(
"{:02}x_entities_{:02}_systems",
entity_bunches, system_amount
),
format!("{entity_bunches:02}x_entities_{system_amount:02}_systems"),
|bencher| {
bencher.iter(|| {
schedule.run(&mut world);
@ -128,10 +125,7 @@ pub fn contrived(criterion: &mut Criterion) {
}
schedule.run(&mut world);
group.bench_function(
format!(
"{:02}x_entities_{:02}_systems",
entity_bunches, system_amount
),
format!("{entity_bunches:02}x_entities_{system_amount:02}_systems"),
|bencher| {
bencher.iter(|| {
schedule.run(&mut world);

View File

@ -37,7 +37,7 @@ pub fn spawn_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [100, 1_000, 10_000] {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@ -68,7 +68,7 @@ pub fn nonempty_spawn_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [100, 1_000, 10_000] {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@ -162,7 +162,7 @@ pub fn fake_commands(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for command_count in [100, 1_000, 10_000] {
group.bench_function(format!("{}_commands", command_count), |bencher| {
group.bench_function(format!("{command_count}_commands"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();
@ -207,7 +207,7 @@ pub fn sized_commands_impl<T: Default + Command>(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for command_count in [100, 1_000, 10_000] {
group.bench_function(format!("{}_commands", command_count), |bencher| {
group.bench_function(format!("{command_count}_commands"), |bencher| {
let mut world = World::default();
let mut command_queue = CommandQueue::default();

View File

@ -13,7 +13,7 @@ pub fn world_despawn(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
bencher.iter_batched_ref(
|| {
let mut world = World::default();

View File

@ -13,7 +13,7 @@ pub fn world_despawn_recursive(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
bencher.iter_batched_ref(
|| {
let mut world = World::default();

View File

@ -13,7 +13,7 @@ pub fn world_spawn(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in [1, 100, 10_000] {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
let mut world = World::default();
bencher.iter(|| {
for _ in 0..entity_count {

View File

@ -49,7 +49,7 @@ pub fn world_entity(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities"), |bencher| {
let world = setup::<Table>(entity_count);
bencher.iter(|| {
@ -72,7 +72,7 @@ pub fn world_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let world = setup::<Table>(entity_count);
bencher.iter(|| {
@ -84,7 +84,7 @@ pub fn world_get(criterion: &mut Criterion) {
}
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let world = setup::<Sparse>(entity_count);
bencher.iter(|| {
@ -107,7 +107,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::<Table>(entity_count);
let mut query = world.query::<&Table>();
@ -120,7 +120,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
group.bench_function(format!("{}_entities_table_wide", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table_wide"), |bencher| {
let mut world = setup_wide::<(
WideTable<0>,
WideTable<1>,
@ -147,7 +147,7 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::<Sparse>(entity_count);
let mut query = world.query::<&Sparse>();
@ -160,37 +160,33 @@ pub fn world_query_get(criterion: &mut Criterion) {
}
});
});
group.bench_function(
format!("{}_entities_sparse_wide", entity_count),
|bencher| {
let mut world = setup_wide::<(
WideSparse<0>,
WideSparse<1>,
WideSparse<2>,
WideSparse<3>,
WideSparse<4>,
WideSparse<5>,
)>(entity_count);
let mut query = world.query::<(
&WideSparse<0>,
&WideSparse<1>,
&WideSparse<2>,
&WideSparse<3>,
&WideSparse<4>,
&WideSparse<5>,
)>();
group.bench_function(format!("{entity_count}_entities_sparse_wide"), |bencher| {
let mut world = setup_wide::<(
WideSparse<0>,
WideSparse<1>,
WideSparse<2>,
WideSparse<3>,
WideSparse<4>,
WideSparse<5>,
)>(entity_count);
let mut query = world.query::<(
&WideSparse<0>,
&WideSparse<1>,
&WideSparse<2>,
&WideSparse<3>,
&WideSparse<4>,
&WideSparse<5>,
)>();
bencher.iter(|| {
for i in 0..entity_count {
// SAFETY: Range is exclusive.
let entity = Entity::from_raw(EntityRow::new(unsafe {
NonMaxU32::new_unchecked(i)
}));
assert!(query.get(&world, entity).is_ok());
}
});
},
);
bencher.iter(|| {
for i in 0..entity_count {
// SAFETY: Range is exclusive.
let entity =
Entity::from_raw(EntityRow::new(unsafe { NonMaxU32::new_unchecked(i) }));
assert!(query.get(&world, entity).is_ok());
}
});
});
}
group.finish();
@ -202,7 +198,7 @@ pub fn world_query_iter(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::<Table>(entity_count);
let mut query = world.query::<&Table>();
@ -216,7 +212,7 @@ pub fn world_query_iter(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::<Sparse>(entity_count);
let mut query = world.query::<&Sparse>();
@ -241,7 +237,7 @@ pub fn world_query_for_each(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = setup::<Table>(entity_count);
let mut query = world.query::<&Table>();
@ -255,7 +251,7 @@ pub fn world_query_for_each(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = setup::<Sparse>(entity_count);
let mut query = world.query::<&Sparse>();
@ -280,7 +276,7 @@ pub fn query_get(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(4));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_entities_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_table"), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Table::default()))
@ -299,7 +295,7 @@ pub fn query_get(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_entities_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_entities_sparse"), |bencher| {
let mut world = World::default();
let mut entities: Vec<_> = world
.spawn_batch((0..entity_count).map(|_| Sparse::default()))
@ -329,7 +325,7 @@ pub fn query_get_many<const N: usize>(criterion: &mut Criterion) {
group.measurement_time(core::time::Duration::from_secs(2 * N as u64));
for entity_count in RANGE.map(|i| i * 10_000) {
group.bench_function(format!("{}_calls_table", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_calls_table"), |bencher| {
let mut world = World::default();
let mut entity_groups: Vec<_> = (0..entity_count)
.map(|_| [(); N].map(|_| world.spawn(Table::default()).id()))
@ -352,7 +348,7 @@ pub fn query_get_many<const N: usize>(criterion: &mut Criterion) {
assert_eq!(black_box(count), entity_count);
});
});
group.bench_function(format!("{}_calls_sparse", entity_count), |bencher| {
group.bench_function(format!("{entity_count}_calls_sparse"), |bencher| {
let mut world = World::default();
let mut entity_groups: Vec<_> = (0..entity_count)
.map(|_| [(); N].map(|_| world.spawn(Sparse::default()).id()))

View File

@ -155,6 +155,7 @@ fn bench(c: &mut Criterion) {
&mesh.positions,
Some(&mesh.normals),
Some(&mesh.indices),
None,
backface_culling,
);

View File

@ -142,7 +142,7 @@ fn concrete_map_apply(criterion: &mut Criterion) {
fn u64_to_n_byte_key(k: u64, n: usize) -> String {
let mut key = String::with_capacity(n);
write!(&mut key, "{}", k).unwrap();
write!(&mut key, "{k}").unwrap();
// Pad key to n bytes.
key.extend(iter::repeat_n('\0', n - key.len()));

View File

@ -55,7 +55,7 @@ fn concrete_struct_field(criterion: &mut Criterion) {
&s,
|bencher, s| {
let field_names = (0..field_count)
.map(|i| format!("field_{}", i))
.map(|i| format!("field_{i}"))
.collect::<Vec<_>>();
bencher.iter(|| {
@ -256,7 +256,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
for i in 0..field_count {
let field_name = format!("field_{}", i);
let field_name = format!("field_{i}");
base.insert(&field_name, 1u32);
}
@ -283,7 +283,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
let mut patch = DynamicStruct::default();
for i in 0..field_count {
let field_name = format!("field_{}", i);
let field_name = format!("field_{i}");
base.insert(&field_name, 0u32);
patch.insert(&field_name, 1u32);
}
@ -309,11 +309,11 @@ fn dynamic_struct_insert(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
let field_name = format!("field_{}", i);
let field_name = format!("field_{i}");
s.insert(&field_name, ());
}
let field = format!("field_{}", field_count);
let field = format!("field_{field_count}");
bencher.iter_batched(
|| s.to_dynamic_struct(),
|mut s| {
@ -339,7 +339,7 @@ fn dynamic_struct_get_field(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
let field_name = format!("field_{}", i);
let field_name = format!("field_{i}");
s.insert(&field_name, ());
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_a11y"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides accessibility support for Bevy Engine"
homepage = "https://bevy.org"
@ -40,10 +40,10 @@ critical-section = [
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
# other
accesskit = { version = "0.19", default-features = false }

View File

@ -26,7 +26,8 @@ use accesskit::Node;
use bevy_app::Plugin;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
prelude::{Component, Event},
component::Component,
event::{BufferedEvent, Event},
resource::Resource,
schedule::SystemSet,
};
@ -44,7 +45,7 @@ use serde::{Deserialize, Serialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// Wrapper struct for [`accesskit::ActionRequest`]. Required to allow it to be used as an `Event`.
#[derive(Event, Deref, DerefMut)]
#[derive(Event, BufferedEvent, Deref, DerefMut)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ActionRequest(pub accesskit::ActionRequest);

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_animation"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides animation functionality for Bevy Engine"
homepage = "https://bevy.org"
@ -10,34 +10,34 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.17.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
bevy_log = { path = "../bevy_log", version = "0.17.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
bevy_mesh = { path = "../bevy_mesh", version = "0.17.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", features = [
"petgraph",
] }
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.17.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
"serialize",
] }
# other
petgraph = { version = "0.7", features = ["serde-1"] }
ron = "0.8"
ron = "0.10"
serde = "1"
blake3 = { version = "1.0" }
downcast-rs = { version = "2", default-features = false, features = ["std"] }
thiserror = { version = "2", default-features = false }
derive_more = { version = "1", default-features = false, features = ["from"] }
derive_more = { version = "2", default-features = false, features = ["from"] }
either = "1.13"
thread_local = "1"
uuid = { version = "1.13.1", features = ["v4"] }

View File

@ -1,10 +1,11 @@
//! The animation graph, which allows animations to be blended together.
use core::{
fmt::Write,
iter,
ops::{Index, IndexMut, Range},
};
use std::io::{self, Write};
use std::io;
use bevy_asset::{
io::Reader, Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, Handle, LoadContext,

View File

@ -324,13 +324,13 @@ impl AnimationClip {
.push(variable_curve);
}
/// Add a untargeted [`Event`] to this [`AnimationClip`].
/// Add an [`EntityEvent`] with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `event` will be cloned and triggered on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
/// See also [`add_event_to_target`](Self::add_event_to_target).
pub fn add_event(&mut self, time: f32, event: impl Event + Clone) {
pub fn add_event(&mut self, time: f32, event: impl EntityEvent + Clone) {
self.add_event_fn(
time,
move |commands: &mut Commands, entity: Entity, _time: f32, _weight: f32| {
@ -339,7 +339,7 @@ impl AnimationClip {
);
}
/// Add an [`Event`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
/// Add an [`EntityEvent`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
///
/// The `event` will be cloned and triggered on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
@ -349,7 +349,7 @@ impl AnimationClip {
&mut self,
target_id: AnimationTargetId,
time: f32,
event: impl Event + Clone,
event: impl EntityEvent + Clone,
) {
self.add_event_fn_to_target(
target_id,
@ -360,19 +360,19 @@ impl AnimationClip {
);
}
/// Add a untargeted event function to this [`AnimationClip`].
/// Add an event function with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `func` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
/// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event`].
/// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event`].
/// See also [`add_event_to_target`](Self::add_event_to_target).
///
/// ```
/// # use bevy_animation::AnimationClip;
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn(1.0, |commands, entity, time, weight| {
/// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
/// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn(
@ -388,14 +388,14 @@ impl AnimationClip {
/// The `func` will trigger on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
///
/// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event_to_target`].
/// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event_to_target`].
/// Use [`add_event`](Self::add_event) instead if you don't have a specific target.
///
/// ```
/// # use bevy_animation::{AnimationClip, AnimationTargetId};
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn_to_target(AnimationTargetId::from_iter(["Arm", "Hand"]), 1.0, |commands, entity, time, weight| {
/// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
/// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn_to_target(
@ -1534,7 +1534,7 @@ mod tests {
use super::*;
#[derive(Event, Reflect, Clone)]
#[derive(Event, EntityEvent, Reflect, Clone)]
struct A;
#[track_caller]

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_anti_aliasing"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides various anti aliasing implementations for Bevy Engine"
homepage = "https://bevy.org"
@ -16,17 +16,17 @@ smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
[dependencies]
# bevy
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.17.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.17.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
# other
tracing = { version = "0.1", default-features = false, features = ["std"] }

View File

@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
FullscreenShader,
};
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_image::BevyDefault as _;
@ -163,7 +163,8 @@ impl Plugin for CasPlugin {
pub struct CasPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
shader: Handle<Shader>,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
}
impl FromWorld for CasPipeline {
@ -187,7 +188,11 @@ impl FromWorld for CasPipeline {
CasPipeline {
texture_bind_group,
sampler,
shader: load_embedded_asset!(render_world, "robust_contrast_adaptive_sharpening.wgsl"),
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(
render_world,
"robust_contrast_adaptive_sharpening.wgsl"
),
}
}
}
@ -209,9 +214,9 @@ impl SpecializedRenderPipeline for CasPipeline {
RenderPipelineDescriptor {
label: Some("contrast_adaptive_sharpening".into()),
layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs,
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {

View File

@ -3,7 +3,7 @@ use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
FullscreenShader,
};
use bevy_ecs::prelude::*;
use bevy_image::BevyDefault as _;
@ -130,7 +130,8 @@ impl Plugin for FxaaPlugin {
pub struct FxaaPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
shader: Handle<Shader>,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
}
impl FromWorld for FxaaPipeline {
@ -157,7 +158,8 @@ impl FromWorld for FxaaPipeline {
FxaaPipeline {
texture_bind_group,
sampler,
shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "fxaa.wgsl"),
}
}
}
@ -181,9 +183,9 @@ impl SpecializedRenderPipeline for FxaaPipeline {
RenderPipelineDescriptor {
label: Some("fxaa".into()),
layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs: vec![
format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(),
format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(),

View File

@ -847,7 +847,7 @@ impl ViewNode for SmaaNode {
view_smaa_uniform_offset,
smaa_textures,
view_smaa_bind_groups,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();

View File

@ -2,9 +2,9 @@ use bevy_app::{App, Plugin};
use bevy_asset::{embedded_asset, load_embedded_asset, Handle};
use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prelude::Camera3d,
prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
FullscreenShader,
};
use bevy_diagnostic::FrameCount;
use bevy_ecs::{
@ -238,7 +238,8 @@ struct TaaPipeline {
taa_bind_group_layout: BindGroupLayout,
nearest_sampler: Sampler,
linear_sampler: Sampler,
shader: Handle<Shader>,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
}
impl FromWorld for TaaPipeline {
@ -283,7 +284,8 @@ impl FromWorld for TaaPipeline {
taa_bind_group_layout,
nearest_sampler,
linear_sampler,
shader: load_embedded_asset!(world, "taa.wgsl"),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "taa.wgsl"),
}
}
}
@ -314,9 +316,9 @@ impl SpecializedRenderPipeline for TaaPipeline {
RenderPipelineDescriptor {
label: Some("taa_pipeline".into()),
layout: vec![self.taa_bind_group_layout.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs,
entry_point: "taa".into(),
targets: vec![

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_app"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides core App functionality for Bevy Engine"
homepage = "https://bevy.org"
@ -79,12 +79,12 @@ hotpatching = [
[dependencies]
# bevy
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false }
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false }
# other
downcast-rs = { version = "2", default-features = false }

View File

@ -106,10 +106,13 @@ impl Default for App {
#[cfg(feature = "bevy_reflect")]
{
use bevy_ecs::observer::ObservedBy;
app.init_resource::<AppTypeRegistry>();
app.register_type::<Name>();
app.register_type::<ChildOf>();
app.register_type::<Children>();
app.register_type::<ObservedBy>();
}
#[cfg(feature = "reflect_functions")]
@ -341,7 +344,7 @@ impl App {
self
}
/// Initializes `T` event handling by inserting an event queue resource ([`Events::<T>`])
/// Initializes [`BufferedEvent`] handling for `T` by inserting an event queue resource ([`Events::<T>`])
/// and scheduling an [`event_update_system`] in [`First`].
///
/// See [`Events`] for information on how to define events.
@ -352,7 +355,7 @@ impl App {
/// # use bevy_app::prelude::*;
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Event)]
/// # #[derive(Event, BufferedEvent)]
/// # struct MyEvent;
/// # let mut app = App::new();
/// #
@ -360,7 +363,7 @@ impl App {
/// ```
pub fn add_event<T>(&mut self) -> &mut Self
where
T: Event,
T: BufferedEvent,
{
self.main_mut().add_event::<T>();
self
@ -1306,7 +1309,7 @@ impl App {
/// Spawns an [`Observer`] entity, which will watch for and respond to the given event.
///
/// `observer` can be any system whose first parameter is a [`Trigger`].
/// `observer` can be any system whose first parameter is [`On`].
///
/// # Examples
///
@ -1322,14 +1325,14 @@ impl App {
/// # friends_allowed: bool,
/// # };
/// #
/// # #[derive(Event)]
/// # #[derive(Event, EntityEvent)]
/// # struct Invite;
/// #
/// # #[derive(Component)]
/// # struct Friend;
/// #
///
/// app.add_observer(|trigger: Trigger<Party>, friends: Query<Entity, With<Friend>>, mut commands: Commands| {
/// app.add_observer(|trigger: On<Party>, friends: Query<Entity, With<Friend>>, mut commands: Commands| {
/// if trigger.event().friends_allowed {
/// for friend in friends.iter() {
/// commands.trigger_targets(Invite, friend);
@ -1404,7 +1407,7 @@ fn run_once(mut app: App) -> AppExit {
app.should_exit().unwrap_or(AppExit::Success)
}
/// An event that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
/// A [`BufferedEvent`] that indicates the [`App`] should exit. If one or more of these are present at the end of an update,
/// the [runner](App::set_runner) will end and ([maybe](App::run)) return control to the caller.
///
/// This event can be used to detect when an exit is requested. Make sure that systems listening
@ -1414,7 +1417,7 @@ fn run_once(mut app: App) -> AppExit {
/// This type is roughly meant to map to a standard definition of a process exit code (0 means success, not 0 means error). Due to portability concerns
/// (see [`ExitCode`](https://doc.rust-lang.org/std/process/struct.ExitCode.html) and [`process::exit`](https://doc.rust-lang.org/std/process/fn.exit.html#))
/// we only allow error codes between 1 and [255](u8::MAX).
#[derive(Event, Debug, Clone, Default, PartialEq, Eq)]
#[derive(Event, BufferedEvent, Debug, Clone, Default, PartialEq, Eq)]
pub enum AppExit {
/// [`App`] exited without any problems.
#[default]
@ -1482,7 +1485,7 @@ mod tests {
change_detection::{DetectChanges, ResMut},
component::Component,
entity::Entity,
event::{Event, EventWriter, Events},
event::{BufferedEvent, Event, EventWriter, Events},
lifecycle::RemovedComponents,
query::With,
resource::Resource,
@ -1579,7 +1582,7 @@ mod tests {
app.add_systems(EnterMainMenu, (foo, bar));
app.world_mut().run_schedule(EnterMainMenu);
assert_eq!(app.world().entities().len(), 2);
assert_eq!(app.world().entity_count(), 2);
}
#[test]
@ -1848,7 +1851,7 @@ mod tests {
}
#[test]
fn events_should_be_updated_once_per_update() {
#[derive(Event, Clone)]
#[derive(Event, BufferedEvent, Clone)]
struct TestEvent;
let mut app = App::new();

View File

@ -88,6 +88,7 @@ impl<C: Component + Clone + PartialEq> core::fmt::Debug for PropagateSet<C> {
}
impl<C: Component + Clone + PartialEq> Eq for PropagateSet<C> {}
impl<C: Component + Clone + PartialEq> core::hash::Hash for PropagateSet<C> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self._p.hash(state);

View File

@ -338,7 +338,7 @@ impl SubApp {
/// See [`App::add_event`].
pub fn add_event<T>(&mut self) -> &mut Self
where
T: Event,
T: BufferedEvent,
{
if !self.world.contains_resource::<Events<T>>() {
EventRegistry::register_event::<T>(self.world_mut());

View File

@ -160,7 +160,7 @@ impl TaskPoolOptions {
pub fn create_default_pools(&self) {
let total_threads = bevy_tasks::available_parallelism()
.clamp(self.min_total_threads, self.max_total_threads);
trace!("Assigning {} cores to default task pools", total_threads);
trace!("Assigning {total_threads} cores to default task pools");
let mut remaining_threads = total_threads;
@ -170,7 +170,7 @@ impl TaskPoolOptions {
.io
.get_number_of_threads(remaining_threads, total_threads);
trace!("IO Threads: {}", io_threads);
trace!("IO Threads: {io_threads}");
remaining_threads = remaining_threads.saturating_sub(io_threads);
IoTaskPool::get_or_init(|| {
@ -200,7 +200,7 @@ impl TaskPoolOptions {
.async_compute
.get_number_of_threads(remaining_threads, total_threads);
trace!("Async Compute Threads: {}", async_compute_threads);
trace!("Async Compute Threads: {async_compute_threads}");
remaining_threads = remaining_threads.saturating_sub(async_compute_threads);
AsyncComputeTaskPool::get_or_init(|| {
@ -231,7 +231,7 @@ impl TaskPoolOptions {
.compute
.get_number_of_threads(remaining_threads, total_threads);
trace!("Compute Threads: {}", compute_threads);
trace!("Compute Threads: {compute_threads}");
ComputeTaskPool::get_or_init(|| {
let builder = TaskPoolBuilder::default()

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_asset"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides asset functionality for Bevy Engine"
homepage = "https://bevy.org"
@ -19,19 +19,19 @@ watch = []
trace = []
[dependencies]
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"bevy_reflect",
] }
bevy_asset_macros = { path = "macros", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
bevy_asset_macros = { path = "macros", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"uuid",
] }
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, features = [
bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false, features = [
"async_executor",
] }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false }
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
] }
@ -54,10 +54,10 @@ parking_lot = { version = "0.12", default-features = false, features = [
"arc_lock",
"send_guard",
] }
ron = { version = "0.8", default-features = false }
ron = { version = "0.10", default-features = false }
serde = { version = "1", default-features = false, features = ["derive"] }
thiserror = { version = "2", default-features = false }
derive_more = { version = "1", default-features = false, features = ["from"] }
derive_more = { version = "2", default-features = false, features = ["from"] }
uuid = { version = "1.13.1", default-features = false, features = [
"v4",
"serde",
@ -65,7 +65,7 @@ uuid = { version = "1.13.1", default-features = false, features = [
tracing = { version = "0.1", default-features = false }
[target.'cfg(target_os = "android")'.dependencies]
bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
[target.'cfg(target_arch = "wasm32")'.dependencies]
# TODO: Assuming all wasm builds are for the browser. Require `no_std` support to break assumption.
@ -78,13 +78,13 @@ web-sys = { version = "0.3", features = [
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
uuid = { version = "1.13.1", default-features = false, features = ["js"] }
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, features = [
bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"web",
] }

View File

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

View File

@ -1,6 +1,7 @@
#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
//! Macros for deriving asset traits.
use bevy_macro_utils::BevyManifest;
use proc_macro::{Span, TokenStream};
use quote::{format_ident, quote};
@ -12,6 +13,7 @@ pub(crate) fn bevy_asset_path() -> Path {
const DEPENDENCY_ATTRIBUTE: &str = "dependency";
/// Implement the `Asset` trait.
#[proc_macro_derive(Asset, attributes(dependency))]
pub fn derive_asset(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
@ -30,6 +32,7 @@ pub fn derive_asset(input: TokenStream) -> TokenStream {
})
}
/// Implement the `VisitAssetDependencies` trait.
#[proc_macro_derive(VisitAssetDependencies, attributes(dependency))]
pub fn derive_asset_dependency_visitor(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);

View File

@ -158,9 +158,9 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
fetch
}
unsafe fn init_fetch<'w>(
unsafe fn init_fetch<'w, 's>(
world: UnsafeWorldCell<'w>,
state: &Self::State,
state: &'s Self::State,
last_run: Tick,
this_run: Tick,
) -> Self::Fetch<'w> {
@ -201,9 +201,9 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
const IS_DENSE: bool = <&A>::IS_DENSE;
unsafe fn set_archetype<'w>(
unsafe fn set_archetype<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
state: &'s Self::State,
archetype: &'w Archetype,
table: &'w Table,
) {
@ -215,7 +215,11 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
}
}
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
unsafe fn set_table<'w, 's>(
fetch: &mut Self::Fetch<'w>,
state: &Self::State,
table: &'w Table,
) {
if let Some(inner) = &mut fetch.inner {
// SAFETY: We delegate to the inner `set_table` for `A`
unsafe {
@ -265,6 +269,7 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
#[inline]
unsafe fn filter_fetch(
state: &Self::State,
fetch: &mut Self::Fetch<'_>,
entity: Entity,
table_row: TableRow,
@ -272,7 +277,7 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
fetch.inner.as_mut().is_some_and(|inner| {
// SAFETY: We delegate to the inner `fetch` for `A`
unsafe {
let handle = <&A>::fetch(inner, entity, table_row);
let handle = <&A>::fetch(&state.asset_id, inner, entity, table_row);
fetch.check.has_changed(handle)
}
})

View File

@ -20,6 +20,7 @@ pub trait DirectAssetAccessExt {
settings: impl Fn(&mut S) + Send + Sync + 'static,
) -> Handle<A>;
}
impl DirectAssetAccessExt for World {
/// Insert an asset similarly to [`Assets::add`].
///

View File

@ -1,12 +1,12 @@
use crate::{Asset, AssetId, AssetLoadError, AssetPath, UntypedAssetId};
use bevy_ecs::event::Event;
use bevy_ecs::event::{BufferedEvent, Event};
use bevy_reflect::Reflect;
use core::fmt::Debug;
/// An event emitted when a specific [`Asset`] fails to load.
/// A [`BufferedEvent`] emitted when a specific [`Asset`] fails to load.
///
/// For an untyped equivalent, see [`UntypedAssetLoadFailedEvent`].
#[derive(Event, Clone, Debug)]
#[derive(Event, BufferedEvent, Clone, Debug)]
pub struct AssetLoadFailedEvent<A: Asset> {
/// The stable identifier of the asset that failed to load.
pub id: AssetId<A>,
@ -24,7 +24,7 @@ impl<A: Asset> AssetLoadFailedEvent<A> {
}
/// An untyped version of [`AssetLoadFailedEvent`].
#[derive(Event, Clone, Debug)]
#[derive(Event, BufferedEvent, Clone, Debug)]
pub struct UntypedAssetLoadFailedEvent {
/// The stable identifier of the asset that failed to load.
pub id: UntypedAssetId,
@ -44,9 +44,9 @@ impl<A: Asset> From<&AssetLoadFailedEvent<A>> for UntypedAssetLoadFailedEvent {
}
}
/// Events that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
/// [`BufferedEvent`]s that occur for a specific loaded [`Asset`], such as "value changed" events and "dependency" events.
#[expect(missing_docs, reason = "Documenting the id fields is unhelpful.")]
#[derive(Event, Reflect)]
#[derive(Event, BufferedEvent, Reflect)]
pub enum AssetEvent<A: Asset> {
/// Emitted whenever an [`Asset`] is added.
Added { id: AssetId<A> },

View File

@ -56,6 +56,7 @@ pub(crate) struct EmbeddedEventHandler {
dir: Dir,
last_event: Option<AssetSourceEvent>,
}
impl FilesystemEventHandler for EmbeddedEventHandler {
fn begin(&mut self) {
self.last_event = None;

View File

@ -141,16 +141,19 @@ impl EmbeddedAssetRegistry {
pub trait GetAssetServer {
fn get_asset_server(&self) -> &AssetServer;
}
impl GetAssetServer for App {
fn get_asset_server(&self) -> &AssetServer {
self.world().get_asset_server()
}
}
impl GetAssetServer for World {
fn get_asset_server(&self) -> &AssetServer {
self.resource()
}
}
impl GetAssetServer for AssetServer {
fn get_asset_server(&self) -> &AssetServer {
self

View File

@ -264,7 +264,7 @@ pub struct AssetPlugin {
/// [`AssetSource`](io::AssetSource). Subfolders within these folders are also valid.
///
/// It is strongly discouraged to use [`Allow`](UnapprovedPathMode::Allow) if your
/// app will include scripts or modding support, as it could allow allow arbitrary file
/// app will include scripts or modding support, as it could allow arbitrary file
/// access for malicious code.
///
/// See [`AssetPath::is_unapproved`](crate::AssetPath::is_unapproved)
@ -272,10 +272,10 @@ pub struct AssetPlugin {
pub enum UnapprovedPathMode {
/// Unapproved asset loading is allowed. This is strongly discouraged.
Allow,
/// Fails to load any asset that is is unapproved, unless an override method is used, like
/// Fails to load any asset that is unapproved, unless an override method is used, like
/// [`AssetServer::load_override`].
Deny,
/// Fails to load any asset that is is unapproved.
/// Fails to load any asset that is unapproved.
#[default]
Forbid,
}

View File

@ -344,7 +344,7 @@ impl<'a> LoadContext<'a> {
/// Begins a new labeled asset load. Use the returned [`LoadContext`] to load
/// dependencies for the new asset and call [`LoadContext::finish`] to finalize the asset load.
/// When finished, make sure you call [`LoadContext::add_labeled_asset`] to add the results back to the parent
/// When finished, make sure you call [`LoadContext::add_loaded_labeled_asset`] to add the results back to the parent
/// context.
/// Prefer [`LoadContext::labeled_asset_scope`] when possible, which will automatically add
/// the labeled [`LoadContext`] back to the parent context.
@ -360,7 +360,7 @@ impl<'a> LoadContext<'a> {
/// # let load_context: LoadContext = panic!();
/// let mut handles = Vec::new();
/// for i in 0..2 {
/// let mut labeled = load_context.begin_labeled_asset();
/// let labeled = load_context.begin_labeled_asset();
/// handles.push(std::thread::spawn(move || {
/// (i.to_string(), labeled.finish(Image::default()))
/// }));
@ -385,7 +385,7 @@ impl<'a> LoadContext<'a> {
/// [`LoadedAsset`], which is registered under the `label` label.
///
/// This exists to remove the need to manually call [`LoadContext::begin_labeled_asset`] and then manually register the
/// result with [`LoadContext::add_labeled_asset`].
/// result with [`LoadContext::add_loaded_labeled_asset`].
///
/// See [`AssetPath`] for more on labeled assets.
pub fn labeled_asset_scope<A: Asset, E>(

View File

@ -18,16 +18,16 @@ pub struct ReflectAsset {
handle_type_id: TypeId,
assets_resource_type_id: TypeId,
get: fn(&World, UntypedHandle) -> Option<&dyn Reflect>,
get: fn(&World, UntypedAssetId) -> Option<&dyn Reflect>,
// SAFETY:
// - may only be called with an [`UnsafeWorldCell`] which can be used to access the corresponding `Assets<T>` resource mutably
// - may only be used to access **at most one** access at once
get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedHandle) -> Option<&mut dyn Reflect>,
get_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>, UntypedAssetId) -> Option<&mut dyn Reflect>,
add: fn(&mut World, &dyn PartialReflect) -> UntypedHandle,
insert: fn(&mut World, UntypedHandle, &dyn PartialReflect),
insert: fn(&mut World, UntypedAssetId, &dyn PartialReflect),
len: fn(&World) -> usize,
ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = UntypedAssetId> + 'w>,
remove: fn(&mut World, UntypedHandle) -> Option<Box<dyn Reflect>>,
remove: fn(&mut World, UntypedAssetId) -> Option<Box<dyn Reflect>>,
}
impl ReflectAsset {
@ -42,15 +42,19 @@ impl ReflectAsset {
}
/// Equivalent of [`Assets::get`]
pub fn get<'w>(&self, world: &'w World, handle: UntypedHandle) -> Option<&'w dyn Reflect> {
(self.get)(world, handle)
pub fn get<'w>(
&self,
world: &'w World,
asset_id: impl Into<UntypedAssetId>,
) -> Option<&'w dyn Reflect> {
(self.get)(world, asset_id.into())
}
/// Equivalent of [`Assets::get_mut`]
pub fn get_mut<'w>(
&self,
world: &'w mut World,
handle: UntypedHandle,
asset_id: impl Into<UntypedAssetId>,
) -> Option<&'w mut dyn Reflect> {
// SAFETY: unique world access
#[expect(
@ -58,7 +62,7 @@ impl ReflectAsset {
reason = "Use of unsafe `Self::get_unchecked_mut()` function."
)]
unsafe {
(self.get_unchecked_mut)(world.as_unsafe_world_cell(), handle)
(self.get_unchecked_mut)(world.as_unsafe_world_cell(), asset_id.into())
}
}
@ -76,8 +80,8 @@ impl ReflectAsset {
/// # let handle_1: UntypedHandle = unimplemented!();
/// # let handle_2: UntypedHandle = unimplemented!();
/// let unsafe_world_cell = world.as_unsafe_world_cell();
/// let a = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, handle_1).unwrap() };
/// let b = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, handle_2).unwrap() };
/// let a = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, &handle_1).unwrap() };
/// let b = unsafe { reflect_asset.get_unchecked_mut(unsafe_world_cell, &handle_2).unwrap() };
/// // ^ not allowed, two mutable references through the same asset resource, even though the
/// // handles are distinct
///
@ -96,10 +100,10 @@ impl ReflectAsset {
pub unsafe fn get_unchecked_mut<'w>(
&self,
world: UnsafeWorldCell<'w>,
handle: UntypedHandle,
asset_id: impl Into<UntypedAssetId>,
) -> Option<&'w mut dyn Reflect> {
// SAFETY: requirements are deferred to the caller
unsafe { (self.get_unchecked_mut)(world, handle) }
unsafe { (self.get_unchecked_mut)(world, asset_id.into()) }
}
/// Equivalent of [`Assets::add`]
@ -107,13 +111,22 @@ impl ReflectAsset {
(self.add)(world, value)
}
/// Equivalent of [`Assets::insert`]
pub fn insert(&self, world: &mut World, handle: UntypedHandle, value: &dyn PartialReflect) {
(self.insert)(world, handle, value);
pub fn insert(
&self,
world: &mut World,
asset_id: impl Into<UntypedAssetId>,
value: &dyn PartialReflect,
) {
(self.insert)(world, asset_id.into(), value);
}
/// Equivalent of [`Assets::remove`]
pub fn remove(&self, world: &mut World, handle: UntypedHandle) -> Option<Box<dyn Reflect>> {
(self.remove)(world, handle)
pub fn remove(
&self,
world: &mut World,
asset_id: impl Into<UntypedAssetId>,
) -> Option<Box<dyn Reflect>> {
(self.remove)(world, asset_id.into())
}
/// Equivalent of [`Assets::len`]
@ -137,17 +150,17 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
ReflectAsset {
handle_type_id: TypeId::of::<Handle<A>>(),
assets_resource_type_id: TypeId::of::<Assets<A>>(),
get: |world, handle| {
get: |world, asset_id| {
let assets = world.resource::<Assets<A>>();
let asset = assets.get(&handle.typed_debug_checked());
let asset = assets.get(asset_id.typed_debug_checked());
asset.map(|asset| asset as &dyn Reflect)
},
get_unchecked_mut: |world, handle| {
get_unchecked_mut: |world, asset_id| {
// SAFETY: `get_unchecked_mut` must be called with `UnsafeWorldCell` having access to `Assets<A>`,
// and must ensure to only have at most one reference to it live at all times.
#[expect(unsafe_code, reason = "Uses `UnsafeWorldCell::get_resource_mut()`.")]
let assets = unsafe { world.get_resource_mut::<Assets<A>>().unwrap().into_inner() };
let asset = assets.get_mut(&handle.typed_debug_checked());
let asset = assets.get_mut(asset_id.typed_debug_checked());
asset.map(|asset| asset as &mut dyn Reflect)
},
add: |world, value| {
@ -156,11 +169,11 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::add`");
assets.add(value).untyped()
},
insert: |world, handle, value| {
insert: |world, asset_id, value| {
let mut assets = world.resource_mut::<Assets<A>>();
let value: A = FromReflect::from_reflect(value)
.expect("could not call `FromReflect::from_reflect` in `ReflectAsset::set`");
assets.insert(&handle.typed_debug_checked(), value);
assets.insert(asset_id.typed_debug_checked(), value);
},
len: |world| {
let assets = world.resource::<Assets<A>>();
@ -170,9 +183,9 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
let assets = world.resource::<Assets<A>>();
Box::new(assets.ids().map(AssetId::untyped))
},
remove: |world, handle| {
remove: |world, asset_id| {
let mut assets = world.resource_mut::<Assets<A>>();
let value = assets.remove(&handle.typed_debug_checked());
let value = assets.remove(asset_id.typed_debug_checked());
value.map(|value| Box::new(value) as Box<dyn Reflect>)
},
}
@ -200,7 +213,7 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
/// let reflect_asset = type_registry.get_type_data::<ReflectAsset>(reflect_handle.asset_type_id()).unwrap();
///
/// let handle = reflect_handle.downcast_handle_untyped(handle.as_any()).unwrap();
/// let value = reflect_asset.get(world, handle).unwrap();
/// let value = reflect_asset.get(world, &handle).unwrap();
/// println!("{value:?}");
/// }
/// ```
@ -210,6 +223,7 @@ pub struct ReflectHandle {
downcast_handle_untyped: fn(&dyn Any) -> Option<UntypedHandle>,
typed: fn(UntypedHandle) -> Box<dyn Reflect>,
}
impl ReflectHandle {
/// The [`TypeId`] of the asset
pub fn asset_type_id(&self) -> TypeId {
@ -247,7 +261,7 @@ mod tests {
use alloc::{string::String, vec::Vec};
use core::any::TypeId;
use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset, UntypedHandle};
use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset};
use bevy_app::App;
use bevy_ecs::reflect::AppTypeRegistry;
use bevy_reflect::Reflect;
@ -281,7 +295,7 @@ mod tests {
let handle = reflect_asset.add(app.world_mut(), &value);
// struct is a reserved keyword, so we can't use it here
let strukt = reflect_asset
.get_mut(app.world_mut(), handle)
.get_mut(app.world_mut(), &handle)
.unwrap()
.reflect_mut()
.as_struct()
@ -294,16 +308,12 @@ mod tests {
assert_eq!(reflect_asset.len(app.world()), 1);
let ids: Vec<_> = reflect_asset.ids(app.world()).collect();
assert_eq!(ids.len(), 1);
let id = ids[0];
let fetched_handle = UntypedHandle::Weak(ids[0]);
let asset = reflect_asset
.get(app.world(), fetched_handle.clone_weak())
.unwrap();
let asset = reflect_asset.get(app.world(), id).unwrap();
assert_eq!(asset.downcast_ref::<AssetType>().unwrap().field, "edited");
reflect_asset
.remove(app.world_mut(), fetched_handle)
.unwrap();
reflect_asset.remove(app.world_mut(), id).unwrap();
assert_eq!(reflect_asset.len(app.world()), 0);
}
}

View File

@ -1931,7 +1931,7 @@ pub enum AssetLoadError {
base_path,
label,
all_labels.len(),
all_labels.iter().map(|l| format!("'{}'", l)).collect::<Vec<_>>().join(", "))]
all_labels.iter().map(|l| format!("'{l}'")).collect::<Vec<_>>().join(", "))]
MissingLabel {
base_path: AssetPath<'static>,
label: String,
@ -1953,6 +1953,14 @@ impl AssetLoaderError {
pub fn path(&self) -> &AssetPath<'static> {
&self.path
}
/// The error the loader reported when attempting to load the asset.
///
/// If you know the type of the error the asset loader returned, you can use
/// [`BevyError::downcast_ref()`] to get it.
pub fn error(&self) -> &BevyError {
&self.error
}
}
/// An error that occurs while resolving an asset added by `add_async`.

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_audio"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Provides audio functionality for Bevy Engine"
homepage = "https://bevy.org"
@ -10,30 +10,36 @@ keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
# other
# TODO: Remove `coreaudio-sys` dep below when updating `cpal`.
rodio = { version = "0.20", default-features = false }
tracing = { version = "0.1", default-features = false, features = ["std"] }
[target.'cfg(target_os = "android")'.dependencies]
cpal = { version = "0.15", optional = true }
[target.'cfg(target_vendor = "apple")'.dependencies]
# NOTE: Explicitly depend on this patch version to fix:
# https://github.com/bevyengine/bevy/issues/18893
coreaudio-sys = { version = "0.2.17", default-features = false }
[target.'cfg(target_arch = "wasm32")'.dependencies]
# TODO: Assuming all wasm builds are for the browser. Require `no_std` support to break assumption.
rodio = { version = "0.20", default-features = false, features = [
"wasm-bindgen",
] }
bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false, features = [
bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false, features = [
"web",
] }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, features = [
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"web",
] }

View File

@ -57,6 +57,7 @@ pub struct PlaybackRemoveMarker;
pub(crate) struct EarPositions<'w, 's> {
pub(crate) query: Query<'w, 's, (Entity, &'static GlobalTransform, &'static SpatialListener)>,
}
impl<'w, 's> EarPositions<'w, 's> {
/// Gets a set of transformed ear positions.
///

View File

@ -344,17 +344,11 @@ mod tests {
assert!(
db_delta.abs() < 1e-2,
"Expected ~{}dB, got {}dB (delta {})",
db,
db_test,
db_delta
"Expected ~{db}dB, got {db_test}dB (delta {db_delta})",
);
assert!(
linear_relative_delta.abs() < 1e-3,
"Expected ~{}, got {} (relative delta {})",
linear,
linear_test,
linear_relative_delta
"Expected ~{linear}, got {linear_test} (relative delta {linear_relative_delta})",
);
}
}
@ -474,15 +468,11 @@ mod tests {
match (a, b) {
(Decibels(a), Decibels(b)) | (Linear(a), Linear(b)) => assert!(
(a - b).abs() < EPSILON,
"Expected {:?} to be approximately equal to {:?}",
a,
b
"Expected {a:?} to be approximately equal to {b:?}",
),
(a, b) => assert!(
(a.to_decibels() - b.to_decibels()).abs() < EPSILON,
"Expected {:?} to be approximately equal to {:?}",
a,
b
"Expected {a:?} to be approximately equal to {b:?}",
),
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_color"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
description = "Types for representing and manipulating color values"
homepage = "https://bevy.org"
@ -10,17 +10,17 @@ keywords = ["bevy", "color"]
rust-version = "1.85.0"
[dependencies]
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false, features = [
bevy_math = { path = "../bevy_math", version = "0.17.0-dev", default-features = false, features = [
"curve",
] }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
bytemuck = { version = "1", features = ["derive"] }
serde = { version = "1.0", features = [
"derive",
], default-features = false, optional = true }
thiserror = { version = "2", default-features = false }
derive_more = { version = "1", default-features = false, features = ["from"] }
wgpu-types = { version = "24", default-features = false, optional = true }
derive_more = { version = "2", default-features = false, features = ["from"] }
wgpu-types = { version = "25", default-features = false, optional = true }
encase = { version = "0.10", default-features = false, optional = true }
[features]

View File

@ -92,7 +92,7 @@ impl Hsla {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Hsla::sequential_dispersed).collect::<Vec<_>>();
/// ```
pub fn sequential_dispersed(index: u32) -> Self {
pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;

View File

@ -96,7 +96,7 @@ impl Lcha {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Lcha::sequential_dispersed).collect::<Vec<_>>();
/// ```
pub fn sequential_dispersed(index: u32) -> Self {
pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;

View File

@ -92,7 +92,7 @@ impl Oklcha {
/// // Palette with 5 distinct hues
/// let palette = (0..5).map(Oklcha::sequential_dispersed).collect::<Vec<_>>();
/// ```
pub fn sequential_dispersed(index: u32) -> Self {
pub const fn sequential_dispersed(index: u32) -> Self {
const FRAC_U32MAX_GOLDEN_RATIO: u32 = 2654435769; // (u32::MAX / Φ) rounded up
const RATIO_360: f32 = 360.0 / u32::MAX as f32;

View File

@ -1,6 +1,6 @@
[package]
name = "bevy_core_pipeline"
version = "0.16.0-dev"
version = "0.17.0-dev"
edition = "2024"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
@ -20,20 +20,20 @@ tonemapping_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.17.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.17.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.17.0-dev" }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
"serialize",
] }

View File

@ -196,6 +196,7 @@ impl RenderAsset for GpuAutoExposureCompensationCurve {
source: Self::SourceAsset,
_: AssetId<Self::SourceAsset>,
(render_device, render_queue): &mut SystemParamItem<Self::Param>,
_: Option<&Self>,
) -> Result<Self, bevy_render::render_asset::PrepareAssetError<Self::SourceAsset>> {
let texture = render_device.create_texture_with_data(
render_queue,

View File

@ -10,7 +10,7 @@ use bevy_render::{
RenderApp,
};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use crate::FullscreenShader;
/// Adds support for specialized "blit pipelines", which can be used to write one texture to another.
pub struct BlitPlugin;
@ -38,7 +38,8 @@ impl Plugin for BlitPlugin {
pub struct BlitPipeline {
pub texture_bind_group: BindGroupLayout,
pub sampler: Sampler,
pub shader: Handle<Shader>,
pub fullscreen_shader: FullscreenShader,
pub fragment_shader: Handle<Shader>,
}
impl FromWorld for BlitPipeline {
@ -61,7 +62,8 @@ impl FromWorld for BlitPipeline {
BlitPipeline {
texture_bind_group,
sampler,
shader: load_embedded_asset!(render_world, "blit.wgsl"),
fullscreen_shader: render_world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(render_world, "blit.wgsl"),
}
}
}
@ -80,9 +82,9 @@ impl SpecializedRenderPipeline for BlitPipeline {
RenderPipelineDescriptor {
label: Some("blit pipeline".into()),
layout: vec![self.texture_bind_group.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "fs_main".into(),
targets: vec![Some(ColorTargetState {

View File

@ -1,5 +1,6 @@
use crate::FullscreenShader;
use super::{Bloom, BLOOM_TEXTURE_FORMAT};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{
prelude::{Component, Entity},
@ -27,8 +28,10 @@ pub struct BloomDownsamplingPipeline {
/// Layout with a texture, a sampler, and uniforms
pub bind_group_layout: BindGroupLayout,
pub sampler: Sampler,
/// The shader asset handle.
pub shader: Handle<Shader>,
/// The asset handle for the fullscreen vertex shader.
pub fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
pub fragment_shader: Handle<Shader>,
}
#[derive(PartialEq, Eq, Hash, Clone)]
@ -81,7 +84,8 @@ impl FromWorld for BloomDownsamplingPipeline {
BloomDownsamplingPipeline {
bind_group_layout,
sampler,
shader: load_embedded_asset!(world, "bloom.wgsl"),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
}
}
}
@ -122,9 +126,9 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
.into(),
),
layout,
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs,
entry_point,
targets: vec![Some(ColorTargetState {

View File

@ -121,7 +121,7 @@ impl ViewNode for BloomNode {
bloom_settings,
upsampling_pipeline_ids,
downsampling_pipeline_ids,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
if bloom_settings.intensity == 0.0 {

View File

@ -227,7 +227,7 @@ impl ExtractComponent for Bloom {
type QueryFilter = With<Hdr>;
type Out = (Self, BloomUniforms);
fn extract_component((bloom, camera): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
fn extract_component((bloom, camera): QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
match (
camera.physical_viewport_rect(),
camera.physical_viewport_size(),

View File

@ -1,7 +1,8 @@
use crate::FullscreenShader;
use super::{
downsampling_pipeline::BloomUniforms, Bloom, BloomCompositeMode, BLOOM_TEXTURE_FORMAT,
};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{
prelude::{Component, Entity},
@ -27,8 +28,10 @@ pub struct UpsamplingPipelineIds {
#[derive(Resource)]
pub struct BloomUpsamplingPipeline {
pub bind_group_layout: BindGroupLayout,
/// The shader asset handle.
pub shader: Handle<Shader>,
/// The asset handle for the fullscreen vertex shader.
pub fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
pub fragment_shader: Handle<Shader>,
}
#[derive(PartialEq, Eq, Hash, Clone)]
@ -58,7 +61,8 @@ impl FromWorld for BloomUpsamplingPipeline {
BloomUpsamplingPipeline {
bind_group_layout,
shader: load_embedded_asset!(world, "bloom.wgsl"),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "bloom.wgsl"),
}
}
}
@ -108,9 +112,9 @@ impl SpecializedRenderPipeline for BloomUpsamplingPipeline {
RenderPipelineDescriptor {
label: Some("bloom_upsampling_pipeline".into()),
layout: vec![self.bind_group_layout.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "upsample".into(),
targets: vec![Some(ColorTargetState {

View File

@ -31,7 +31,7 @@ impl ViewNode for MainOpaquePass2dNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(camera, view, target, depth): QueryItem<'w, Self::ViewQuery>,
(camera, view, target, depth): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (

View File

@ -28,7 +28,7 @@ impl ViewNode for MainTransparentPass2dNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, Self::ViewQuery>,
(camera, view, target, depth): bevy_ecs::query::QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let Some(transparent_phases) =

View File

@ -80,6 +80,7 @@ impl From<TextureUsages> for Camera3dDepthTextureUsage {
Self(value.bits())
}
}
impl From<Camera3dDepthTextureUsage> for TextureUsages {
fn from(value: Camera3dDepthTextureUsage) -> Self {
Self::from_bits_truncate(value.0)

View File

@ -45,7 +45,7 @@ impl ViewNode for MainOpaquePass3dNode {
skybox_pipeline,
skybox_bind_group,
view_uniform_offset,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (Some(opaque_phases), Some(alpha_mask_phases)) = (

View File

@ -1,6 +1,6 @@
use crate::{
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prepass::{DeferredPrepass, ViewPrepassTextures},
FullscreenShader,
};
use bevy_app::prelude::*;
use bevy_asset::{embedded_asset, load_embedded_asset};
@ -130,6 +130,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
),
);
let vertex_state = world.resource::<FullscreenShader>().to_vertex_state();
let shader = load_embedded_asset!(world, "copy_deferred_lighting_id.wgsl");
let pipeline_id =
@ -138,7 +139,7 @@ impl FromWorld for CopyDeferredLightingIdPipeline {
.queue_render_pipeline(RenderPipelineDescriptor {
label: Some("copy_deferred_lighting_id_pipeline".into()),
layout: vec![layout.clone()],
vertex: fullscreen_shader_vertex_state(),
vertex: vertex_state,
fragment: Some(FragmentState {
shader,
shader_defs: vec![],

View File

@ -36,7 +36,7 @@ impl ViewNode for EarlyDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
run_deferred_prepass(
@ -74,7 +74,7 @@ impl ViewNode for LateDeferredGBufferPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let (_, _, _, _, occlusion_culling, no_indirect_drawing) = view_query;
@ -107,6 +107,7 @@ fn run_deferred_prepass<'w>(
render_context: &mut RenderContext<'w>,
(camera, extracted_view, view_depth_texture, view_prepass_textures, _, _): QueryItem<
'w,
'_,
<LateDeferredGBufferPrepassNode as ViewNode>::ViewQuery,
>,
is_late: bool,

View File

@ -66,7 +66,7 @@ use crate::{
graph::{Core3d, Node3d},
Camera3d, DEPTH_TEXTURE_SAMPLING_SUPPORTED,
},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
FullscreenShader,
};
/// A plugin that adds support for the depth of field effect to Bevy.
@ -325,8 +325,10 @@ pub struct DepthOfFieldPipeline {
/// The bind group layout shared among all invocations of the depth of field
/// shader.
global_bind_group_layout: BindGroupLayout,
/// The shader asset handle.
shader: Handle<Shader>,
/// The asset handle for the fullscreen vertex shader.
fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
fragment_shader: Handle<Shader>,
}
impl ViewNode for DepthOfFieldNode {
@ -352,7 +354,7 @@ impl ViewNode for DepthOfFieldNode {
view_bind_group_layouts,
depth_of_field_uniform_index,
auxiliary_dof_texture,
): QueryItem<'w, Self::ViewQuery>,
): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();
@ -678,13 +680,15 @@ pub fn prepare_depth_of_field_pipelines(
&ViewDepthOfFieldBindGroupLayouts,
&Msaa,
)>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
) {
for (entity, view, depth_of_field, view_bind_group_layouts, msaa) in view_targets.iter() {
let dof_pipeline = DepthOfFieldPipeline {
view_bind_group_layouts: view_bind_group_layouts.clone(),
global_bind_group_layout: global_bind_group_layout.layout.clone(),
shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
fullscreen_shader: fullscreen_shader.clone(),
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "dof.wgsl"),
};
// We'll need these two flags to create the `DepthOfFieldPipelineKey`s.
@ -797,12 +801,12 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline {
label: Some("depth of field pipeline".into()),
layout,
push_constant_ranges: vec![],
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
primitive: default(),
depth_stencil: None,
multisample: default(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs,
entry_point: match key.pass {
DofPass::GaussianHorizontal => "gaussian_horizontal".into(),

View File

@ -1,25 +1,40 @@
use bevy_asset::{weak_handle, Handle};
use bevy_asset::{load_embedded_asset, Handle};
use bevy_ecs::{resource::Resource, world::FromWorld};
use bevy_render::{prelude::Shader, render_resource::VertexState};
pub const FULLSCREEN_SHADER_HANDLE: Handle<Shader> =
weak_handle!("481fb759-d0b1-4175-8319-c439acde30a2");
/// A shader that renders to the whole screen. Useful for post-processing.
#[derive(Resource, Clone)]
pub struct FullscreenShader(Handle<Shader>);
/// uses the [`FULLSCREEN_SHADER_HANDLE`] to output a
/// ```wgsl
/// struct FullscreenVertexOutput {
/// [[builtin(position)]]
/// position: vec4<f32>;
/// [[location(0)]]
/// uv: vec2<f32>;
/// };
/// ```
/// from the vertex shader.
/// The draw call should render one triangle: `render_pass.draw(0..3, 0..1);`
pub fn fullscreen_shader_vertex_state() -> VertexState {
VertexState {
shader: FULLSCREEN_SHADER_HANDLE,
shader_defs: Vec::new(),
entry_point: "fullscreen_vertex_shader".into(),
buffers: Vec::new(),
impl FromWorld for FullscreenShader {
fn from_world(world: &mut bevy_ecs::world::World) -> Self {
Self(load_embedded_asset!(world, "fullscreen.wgsl"))
}
}
impl FullscreenShader {
/// Gets the raw shader handle.
pub fn shader(&self) -> Handle<Shader> {
self.0.clone()
}
/// Creates a [`VertexState`] that uses the [`FullscreenShader`] to output a
/// ```wgsl
/// struct FullscreenVertexOutput {
/// @builtin(position)
/// position: vec4<f32>;
/// @location(0)
/// uv: vec2<f32>;
/// };
/// ```
/// from the vertex shader.
/// The draw call should render one triangle: `render_pass.draw(0..3, 0..1);`
pub fn to_vertex_state(&self) -> VertexState {
VertexState {
shader: self.0.clone(),
shader_defs: Vec::new(),
entry_point: "fullscreen_vertex_shader".into(),
buffers: Vec::new(),
}
}
}

View File

@ -14,18 +14,20 @@ pub mod core_3d;
pub mod deferred;
pub mod dof;
pub mod experimental;
pub mod fullscreen_vertex_shader;
pub mod motion_blur;
pub mod msaa_writeback;
pub mod oit;
pub mod post_process;
pub mod prepass;
mod skybox;
pub mod tonemapping;
pub mod upscaling;
pub use fullscreen_vertex_shader::FullscreenShader;
pub use skybox::Skybox;
mod fullscreen_vertex_shader;
mod skybox;
/// The core pipeline prelude.
///
/// This includes the most common types in this crate, re-exported for your convenience.
@ -42,7 +44,6 @@ use crate::{
deferred::copy_lighting_id::CopyDeferredLightingIdPlugin,
dof::DepthOfFieldPlugin,
experimental::mip_generation::MipGenerationPlugin,
fullscreen_vertex_shader::FULLSCREEN_SHADER_HANDLE,
motion_blur::MotionBlurPlugin,
msaa_writeback::MsaaWritebackPlugin,
post_process::PostProcessingPlugin,
@ -51,8 +52,8 @@ use crate::{
upscaling::UpscalingPlugin,
};
use bevy_app::{App, Plugin};
use bevy_asset::load_internal_asset;
use bevy_render::prelude::Shader;
use bevy_asset::embedded_asset;
use bevy_render::RenderApp;
use oit::OrderIndependentTransparencyPlugin;
#[derive(Default)]
@ -60,17 +61,13 @@ pub struct CorePipelinePlugin;
impl Plugin for CorePipelinePlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(
app,
FULLSCREEN_SHADER_HANDLE,
"fullscreen_vertex_shader/fullscreen.wgsl",
Shader::from_wgsl
);
embedded_asset!(app, "fullscreen_vertex_shader/fullscreen.wgsl");
app.register_type::<DepthPrepass>()
.register_type::<NormalPrepass>()
.register_type::<MotionVectorPrepass>()
.register_type::<DeferredPrepass>()
.init_resource::<FullscreenShader>()
.add_plugins((Core2dPlugin, Core3dPlugin, CopyDeferredLightingIdPlugin))
.add_plugins((
BlitPlugin,
@ -85,4 +82,11 @@ impl Plugin for CorePipelinePlugin {
MipGenerationPlugin,
));
}
fn finish(&self, app: &mut App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app.init_resource::<FullscreenShader>();
}
}

View File

@ -25,7 +25,7 @@ use bevy_render::{
view::{ExtractedView, Msaa, ViewTarget},
};
use crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use crate::FullscreenShader;
use super::MotionBlurUniform;
@ -34,11 +34,16 @@ pub struct MotionBlurPipeline {
pub(crate) sampler: Sampler,
pub(crate) layout: BindGroupLayout,
pub(crate) layout_msaa: BindGroupLayout,
pub(crate) shader: Handle<Shader>,
pub(crate) fullscreen_shader: FullscreenShader,
pub(crate) fragment_shader: Handle<Shader>,
}
impl MotionBlurPipeline {
pub(crate) fn new(render_device: &RenderDevice, shader: Handle<Shader>) -> Self {
pub(crate) fn new(
render_device: &RenderDevice,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
) -> Self {
let mb_layout = &BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
@ -84,7 +89,8 @@ impl MotionBlurPipeline {
sampler,
layout,
layout_msaa,
shader,
fullscreen_shader,
fragment_shader,
}
}
}
@ -93,8 +99,9 @@ impl FromWorld for MotionBlurPipeline {
fn from_world(render_world: &mut bevy_ecs::world::World) -> Self {
let render_device = render_world.resource::<RenderDevice>().clone();
let shader = load_embedded_asset!(render_world, "motion_blur.wgsl");
MotionBlurPipeline::new(&render_device, shader)
let fullscreen_shader = render_world.resource::<FullscreenShader>().clone();
let fragment_shader = load_embedded_asset!(render_world, "motion_blur.wgsl");
MotionBlurPipeline::new(&render_device, fullscreen_shader, fragment_shader)
}
}
@ -128,9 +135,9 @@ impl SpecializedRenderPipeline for MotionBlurPipeline {
RenderPipelineDescriptor {
label: Some("motion_blur_pipeline".into()),
layout,
vertex: fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs,
entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {

View File

@ -61,7 +61,7 @@ impl ViewNode for MsaaWritebackNode {
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(target, blit_pipeline_id, msaa): QueryItem<'w, Self::ViewQuery>,
(target, blit_pipeline_id, msaa): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
if *msaa == Msaa::Off {

View File

@ -1,7 +1,4 @@
use crate::{
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
oit::OrderIndependentTransparencySettings,
};
use crate::{oit::OrderIndependentTransparencySettings, FullscreenShader};
use bevy_app::Plugin;
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer};
use bevy_derive::Deref;
@ -156,6 +153,7 @@ pub fn queue_oit_resolve_pipeline(
),
With<OrderIndependentTransparencySettings>,
>,
fullscreen_shader: Res<FullscreenShader>,
asset_server: Res<AssetServer>,
// Store the key with the id to make the clean up logic easier.
// This also means it will always replace the entry if the key changes so nothing to clean up.
@ -176,7 +174,12 @@ pub fn queue_oit_resolve_pipeline(
}
}
let desc = specialize_oit_resolve_pipeline(key, &resolve_pipeline, &asset_server);
let desc = specialize_oit_resolve_pipeline(
key,
&resolve_pipeline,
&fullscreen_shader,
&asset_server,
);
let pipeline_id = pipeline_cache.queue_render_pipeline(desc);
commands.entity(e).insert(OitResolvePipelineId(pipeline_id));
@ -194,6 +197,7 @@ pub fn queue_oit_resolve_pipeline(
fn specialize_oit_resolve_pipeline(
key: OitResolvePipelineKey,
resolve_pipeline: &OitResolvePipeline,
fullscreen_shader: &FullscreenShader,
asset_server: &AssetServer,
) -> RenderPipelineDescriptor {
let format = if key.hdr {
@ -224,7 +228,7 @@ fn specialize_oit_resolve_pipeline(
write_mask: ColorWrites::ALL,
})],
}),
vertex: fullscreen_shader_vertex_state(),
vertex: fullscreen_shader.to_vertex_state(),
primitive: PrimitiveState::default(),
depth_stencil: None,
multisample: MultisampleState::default(),

View File

@ -44,7 +44,7 @@ use bevy_utils::prelude::default;
use crate::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader,
FullscreenShader,
};
/// The handle to the default chromatic aberration lookup texture.
@ -130,8 +130,10 @@ pub struct PostProcessingPipeline {
source_sampler: Sampler,
/// Specifies how to sample the chromatic aberration gradient.
chromatic_aberration_lut_sampler: Sampler,
/// The shader asset handle.
shader: Handle<Shader>,
/// The asset handle for the fullscreen vertex shader.
fullscreen_shader: FullscreenShader,
/// The fragment shader asset handle.
fragment_shader: Handle<Shader>,
}
/// A key that uniquely identifies a built-in postprocessing pipeline.
@ -308,7 +310,8 @@ impl FromWorld for PostProcessingPipeline {
bind_group_layout,
source_sampler,
chromatic_aberration_lut_sampler,
shader: load_embedded_asset!(world, "post_process.wgsl"),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "post_process.wgsl"),
}
}
}
@ -320,9 +323,9 @@ impl SpecializedRenderPipeline for PostProcessingPipeline {
RenderPipelineDescriptor {
label: Some("postprocessing".into()),
layout: vec![self.bind_group_layout.clone()],
vertex: fullscreen_vertex_shader::fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "fragment_main".into(),
targets: vec![Some(ColorTargetState {
@ -352,7 +355,7 @@ impl ViewNode for PostProcessingNode {
&self,
_: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, Self::ViewQuery>,
(view_target, pipeline_id, chromatic_aberration, post_processing_uniform_buffer_offsets): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::<PipelineCache>();
@ -485,7 +488,7 @@ impl ExtractComponent for ChromaticAberration {
type Out = ChromaticAberration;
fn extract_component(
chromatic_aberration: QueryItem<'_, Self::QueryData>,
chromatic_aberration: QueryItem<'_, '_, Self::QueryData>,
) -> Option<Self::Out> {
// Skip the postprocessing phase entirely if the intensity is zero.
if chromatic_aberration.intensity > 0.0 {

View File

@ -74,11 +74,16 @@ pub struct MotionVectorPrepass;
#[reflect(Component, Default)]
pub struct DeferredPrepass;
/// View matrices from the previous frame.
///
/// Useful for temporal rendering techniques that need access to last frame's camera data.
#[derive(Component, ShaderType, Clone)]
pub struct PreviousViewData {
pub view_from_world: Mat4,
pub clip_from_world: Mat4,
pub clip_from_view: Mat4,
pub world_from_clip: Mat4,
pub view_from_clip: Mat4,
}
#[derive(Resource, Default)]

View File

@ -36,7 +36,7 @@ impl ViewNode for EarlyPrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
view_query: QueryItem<'w, Self::ViewQuery>,
view_query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
run_prepass(graph, render_context, view_query, world, "early prepass")
@ -73,7 +73,7 @@ impl ViewNode for LatePrepassNode {
&self,
graph: &mut RenderGraphContext,
render_context: &mut RenderContext<'w>,
query: QueryItem<'w, Self::ViewQuery>,
query: QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
// We only need a late prepass if we have occlusion culling and indirect
@ -112,7 +112,7 @@ fn run_prepass<'w>(
_,
_,
has_deferred,
): QueryItem<'w, <LatePrepassNode as ViewNode>::ViewQuery>,
): QueryItem<'w, '_, <LatePrepassNode as ViewNode>::ViewQuery>,
world: &'w World,
label: &'static str,
) -> Result<(), NodeRunError> {

View File

@ -113,7 +113,9 @@ impl ExtractComponent for Skybox {
type QueryFilter = ();
type Out = (Self, SkyboxUniforms);
fn extract_component((skybox, exposure): QueryItem<'_, Self::QueryData>) -> Option<Self::Out> {
fn extract_component(
(skybox, exposure): QueryItem<'_, '_, Self::QueryData>,
) -> Option<Self::Out> {
let exposure = exposure
.map(Exposure::exposure)
.unwrap_or_else(|| Exposure::default().exposure());
@ -123,7 +125,7 @@ impl ExtractComponent for Skybox {
SkyboxUniforms {
brightness: skybox.brightness * exposure,
transform: Transform::from_rotation(skybox.rotation)
.compute_matrix()
.to_matrix()
.inverse(),
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
_wasm_padding_8b: 0,

View File

@ -27,7 +27,7 @@ use crate::{
prepass_target_descriptors, MotionVectorPrepass, NormalPrepass, PreviousViewData,
PreviousViewUniforms,
},
Skybox,
FullscreenShader, Skybox,
};
/// This pipeline writes motion vectors to the prepass for all [`Skybox`]es.
@ -38,7 +38,8 @@ use crate::{
#[derive(Resource)]
pub struct SkyboxPrepassPipeline {
bind_group_layout: BindGroupLayout,
shader: Handle<Shader>,
fullscreen_shader: FullscreenShader,
fragment_shader: Handle<Shader>,
}
/// Used to specialize the [`SkyboxPrepassPipeline`].
@ -73,7 +74,8 @@ impl FromWorld for SkyboxPrepassPipeline {
),
),
),
shader: load_embedded_asset!(world, "skybox_prepass.wgsl"),
fullscreen_shader: world.resource::<FullscreenShader>().clone(),
fragment_shader: load_embedded_asset!(world, "skybox_prepass.wgsl"),
}
}
}
@ -86,7 +88,7 @@ impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
label: Some("skybox_prepass_pipeline".into()),
layout: vec![self.bind_group_layout.clone()],
push_constant_ranges: vec![],
vertex: crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state(),
vertex: self.fullscreen_shader.to_vertex_state(),
primitive: default(),
depth_stencil: Some(DepthStencilState {
format: CORE_3D_DEPTH_FORMAT,
@ -101,7 +103,7 @@ impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
alpha_to_coverage_enabled: false,
},
fragment: Some(FragmentState {
shader: self.shader.clone(),
shader: self.fragment_shader.clone(),
shader_defs: vec![],
entry_point: "fragment".into(),
targets: prepass_target_descriptors(key.normal_prepass, true, false),

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