Merge branch 'main' of https://github.com/bevyengine/bevy into reflect-auto-registration
This commit is contained in:
commit
e18aaefef2
4
.github/start-wasm-example/package.json
vendored
4
.github/start-wasm-example/package.json
vendored
@ -8,9 +8,9 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.28.1"
|
||||
"@playwright/test": "^1.49.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -155,6 +155,7 @@ jobs:
|
||||
build-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@ -175,6 +176,7 @@ jobs:
|
||||
build-wasm-atomics:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@ -397,6 +399,7 @@ jobs:
|
||||
msrv:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
|
||||
147
.github/workflows/daily.yml
vendored
147
.github/workflows/daily.yml
vendored
@ -1,147 +0,0 @@
|
||||
name: Daily Jobs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 12 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build-for-iOS:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Add iOS targets
|
||||
run: rustup target add aarch64-apple-ios x86_64-apple-ios
|
||||
|
||||
- name: Build app for iOS
|
||||
run: |
|
||||
cd examples/mobile
|
||||
make xcodebuild-iphone
|
||||
mkdir Payload
|
||||
mv build/Build/Products/Debug-iphoneos/bevy_mobile_example.app Payload
|
||||
zip -r bevy_mobile_example.zip Payload
|
||||
mv bevy_mobile_example.zip bevy_mobile_example.ipa
|
||||
|
||||
- name: Upload to Browser Stack
|
||||
run: |
|
||||
curl -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \
|
||||
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
|
||||
-F "file=@examples/mobile/bevy_mobile_example.ipa" \
|
||||
-F "custom_id=$GITHUB_RUN_ID"
|
||||
|
||||
build-for-Android:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Add Android targets
|
||||
run: rustup target add aarch64-linux-android
|
||||
|
||||
- name: Install Cargo NDK
|
||||
run: cargo install --force cargo-ndk
|
||||
|
||||
- name: Build .so file
|
||||
run: cargo ndk -t arm64-v8a -o android_example/app/src/main/jniLibs build --package bevy_mobile_example
|
||||
env:
|
||||
# This will reduce the APK size from 1GB to ~200MB
|
||||
CARGO_PROFILE_DEV_DEBUG: false
|
||||
|
||||
- name: Build app for Android
|
||||
run: cd examples/mobile/android_example && chmod +x gradlew && ./gradlew build
|
||||
|
||||
- name: Upload to Browser Stack
|
||||
run: |
|
||||
curl -u "${{ secrets.BROWSERSTACK_USERNAME }}:${{ secrets.BROWSERSTACK_ACCESS_KEY }}" \
|
||||
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
|
||||
-F "file=@app/build/outputs/apk/debug/app-debug.apk" \
|
||||
-F "custom_id=$GITHUB_RUN_ID"
|
||||
|
||||
nonce:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
outputs:
|
||||
result: ${{ steps.nonce.outputs.result }}
|
||||
steps:
|
||||
- id: nonce
|
||||
run: echo "result=${{ github.run_id }}-$(date +%s)" >> $GITHUB_OUTPUT
|
||||
|
||||
run:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: [nonce, build-for-iOS, build-for-Android]
|
||||
env:
|
||||
PERCY_PARALLEL_NONCE: ${{ needs.nonce.outputs.result }}
|
||||
PERCY_PARALLEL_TOTAL: ${{ strategy.job-total }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- device: "iPhone 13"
|
||||
os_version: "15"
|
||||
- device: "iPhone 14"
|
||||
os_version: "16"
|
||||
- device: "iPhone 15"
|
||||
os_version: "17"
|
||||
- device: "Xiaomi Redmi Note 11"
|
||||
os_version: "11.0"
|
||||
- device: "Google Pixel 6"
|
||||
os_version: "12.0"
|
||||
- device: "Samsung Galaxy S23"
|
||||
os_version: "13.0"
|
||||
- device: "Google Pixel 8"
|
||||
os_version: "14.0"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run Example
|
||||
run: |
|
||||
cd .github/start-mobile-example
|
||||
npm install
|
||||
npm install -g @percy/cli@latest
|
||||
npx percy app:exec --parallel -- npm run mobile
|
||||
env:
|
||||
BROWSERSTACK_APP_ID: ${{ github.run_id }}
|
||||
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
|
||||
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
|
||||
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
|
||||
DEVICE: ${{ matrix.device }}
|
||||
OS_VERSION: ${{ matrix.os_version }}
|
||||
|
||||
- name: Save screenshots
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: screenshots-${{ matrix.device }}-${{ matrix.os_version }}
|
||||
path: .github/start-mobile-example/*.png
|
||||
|
||||
check-result:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: [run]
|
||||
steps:
|
||||
- name: Wait for screenshots comparison
|
||||
run: |
|
||||
npm install -g @percy/cli@latest
|
||||
npx percy build:wait --project dede4209/Bevy-Mobile-Example --commit ${{ github.sha }} --fail-on-changes --pass-if-approved
|
||||
env:
|
||||
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
|
||||
5
.github/workflows/post-release.yml
vendored
5
.github/workflows/post-release.yml
vendored
@ -8,9 +8,12 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
bump:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
55
.github/workflows/release.yml
vendored
55
.github/workflows/release.yml
vendored
@ -1,55 +0,0 @@
|
||||
name: Release
|
||||
|
||||
# how to trigger: https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
if: github.repository == 'bevyengine/bevy'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install cargo-release
|
||||
run: cargo install cargo-release
|
||||
|
||||
- name: Setup release
|
||||
run: |
|
||||
# Set the commit author to the github-actions bot. See discussion here for more information:
|
||||
# https://github.com/actions/checkout/issues/13#issuecomment-724415212
|
||||
# https://github.community/t/github-actions-bot-email-address/17204/6
|
||||
git config user.name 'Bevy Auto Releaser'
|
||||
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
# release: remove the dev suffix, like going from 0.X.0-dev to 0.X.0
|
||||
# --workspace: updating all crates in the workspace
|
||||
# --no-publish: do not publish to crates.io
|
||||
# --execute: not a dry run
|
||||
# --no-tag: do not push tag for each new version
|
||||
# --no-push: do not push the update commits
|
||||
# --dependent-version upgrade: change 0.X.0-dev in internal dependencies to 0.X.0
|
||||
# --exclude: ignore those packages
|
||||
cargo release release \
|
||||
--workspace \
|
||||
--no-publish \
|
||||
--execute \
|
||||
--no-tag \
|
||||
--no-confirm \
|
||||
--no-push \
|
||||
--dependent-version upgrade \
|
||||
--exclude ci \
|
||||
--exclude errors \
|
||||
--exclude bevy_mobile_example \
|
||||
--exclude build-wasm-example
|
||||
|
||||
- name: Create PR
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
delete-branch: true
|
||||
base: "main"
|
||||
title: "Preparing Next Release"
|
||||
body: |
|
||||
Preparing next release. This PR has been auto-generated.
|
||||
8
.github/workflows/validation-jobs.yml
vendored
8
.github/workflows/validation-jobs.yml
vendored
@ -80,7 +80,7 @@ jobs:
|
||||
run-examples-linux-vulkan:
|
||||
# also run when pushed to main to update reference screenshots
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -90,7 +90,7 @@ jobs:
|
||||
- name: Install additional Linux dependencies for Vulkan
|
||||
run: |
|
||||
sudo add-apt-repository ppa:kisak/turtle -y
|
||||
sudo apt-get install --no-install-recommends libxkbcommon-x11-0 xvfb libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
sudo apt-get install --no-install-recommends libxkbcommon-x11-0 xvfb libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
@ -185,7 +185,7 @@ jobs:
|
||||
|
||||
run-examples-on-wasm:
|
||||
if: ${{ github.event_name == 'merge_group' }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -210,7 +210,7 @@ jobs:
|
||||
sudo apt-get update -y -qq
|
||||
sudo add-apt-repository ppa:kisak/turtle -y
|
||||
sudo apt-get update
|
||||
sudo apt install -y xvfb libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
sudo apt install -y xvfb libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers
|
||||
|
||||
- name: Install wasm-bindgen
|
||||
run: cargo install --force wasm-bindgen-cli
|
||||
|
||||
107
Cargo.toml
107
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
categories = ["game-engines", "graphics", "gui", "rendering"]
|
||||
description = "A refreshingly simple data-driven game engine and app framework"
|
||||
@ -41,6 +41,7 @@ type_complexity = "allow"
|
||||
undocumented_unsafe_blocks = "warn"
|
||||
unwrap_or_default = "warn"
|
||||
needless_lifetimes = "allow"
|
||||
too_many_arguments = "allow"
|
||||
|
||||
ptr_as_ptr = "warn"
|
||||
ptr_cast_constness = "warn"
|
||||
@ -53,6 +54,9 @@ std_instead_of_core = "warn"
|
||||
std_instead_of_alloc = "warn"
|
||||
alloc_instead_of_core = "warn"
|
||||
|
||||
allow_attributes = "warn"
|
||||
allow_attributes_without_reason = "warn"
|
||||
|
||||
[workspace.lints.rust]
|
||||
missing_docs = "warn"
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] }
|
||||
@ -82,6 +86,7 @@ type_complexity = "allow"
|
||||
undocumented_unsafe_blocks = "warn"
|
||||
unwrap_or_default = "warn"
|
||||
needless_lifetimes = "allow"
|
||||
too_many_arguments = "allow"
|
||||
|
||||
ptr_as_ptr = "warn"
|
||||
ptr_cast_constness = "warn"
|
||||
@ -93,6 +98,9 @@ std_instead_of_core = "allow"
|
||||
std_instead_of_alloc = "allow"
|
||||
alloc_instead_of_core = "allow"
|
||||
|
||||
allow_attributes = "warn"
|
||||
allow_attributes_without_reason = "warn"
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] }
|
||||
@ -214,7 +222,6 @@ bevy_sprite = [
|
||||
"bevy_render",
|
||||
"bevy_core_pipeline",
|
||||
"bevy_color",
|
||||
"bevy_sprite_picking_backend",
|
||||
]
|
||||
|
||||
# Provides text functionality
|
||||
@ -227,7 +234,6 @@ bevy_ui = [
|
||||
"bevy_text",
|
||||
"bevy_sprite",
|
||||
"bevy_color",
|
||||
"bevy_ui_picking_backend",
|
||||
]
|
||||
|
||||
# Windowing layer
|
||||
@ -471,11 +477,11 @@ custom_cursor = ["bevy_internal/custom_cursor"]
|
||||
ghost_nodes = ["bevy_internal/ghost_nodes"]
|
||||
|
||||
[dependencies]
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.15.0-dev", default-features = false }
|
||||
bevy_internal = { path = "crates/bevy_internal", version = "0.16.0-dev", default-features = false }
|
||||
|
||||
# Wasm does not support dynamic linking.
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
bevy_dylib = { path = "crates/bevy_dylib", version = "0.15.0-dev", default-features = false, optional = true }
|
||||
bevy_dylib = { path = "crates/bevy_dylib", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.0"
|
||||
@ -485,7 +491,7 @@ flate2 = "1.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
bytemuck = "1.7"
|
||||
bevy_render = { path = "crates/bevy_render", version = "0.15.0-dev", default-features = false }
|
||||
bevy_render = { path = "crates/bevy_render", version = "0.16.0-dev", default-features = false }
|
||||
# Needed to poll Task examples
|
||||
futures-lite = "2.0.1"
|
||||
async-std = "1.13"
|
||||
@ -949,6 +955,17 @@ description = "Illustrates bloom configuration using HDR and emissive materials"
|
||||
category = "3D Rendering"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "decal"
|
||||
path = "examples/3d/decal.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.decal]
|
||||
name = "Decal"
|
||||
description = "Decal rendering"
|
||||
category = "3D Rendering"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "deferred_rendering"
|
||||
path = "examples/3d/deferred_rendering.rs"
|
||||
@ -1236,11 +1253,16 @@ description = "Meshlet rendering for dense high-poly scenes (experimental)"
|
||||
category = "3D Rendering"
|
||||
wasm = false
|
||||
setup = [
|
||||
[
|
||||
"mkdir",
|
||||
"-p",
|
||||
"assets/external/models",
|
||||
],
|
||||
[
|
||||
"curl",
|
||||
"-o",
|
||||
"assets/models/bunny.meshlet_mesh",
|
||||
"https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/defbd9b32072624d40d57de7d345c66a9edf5d0b/bunny.meshlet_mesh",
|
||||
"assets/external/models/bunny.meshlet_mesh",
|
||||
"https://raw.githubusercontent.com/JMS55/bevy_meshlet_asset/7a7c14138021f63904b584d5f7b73b695c7f4bbf/bunny.meshlet_mesh",
|
||||
],
|
||||
]
|
||||
|
||||
@ -1287,13 +1309,35 @@ category = "Animation"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "animated_fox"
|
||||
path = "examples/animation/animated_fox.rs"
|
||||
name = "animated_mesh"
|
||||
path = "examples/animation/animated_mesh.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.animated_fox]
|
||||
name = "Animated Fox"
|
||||
description = "Plays an animation from a skinned glTF"
|
||||
[package.metadata.example.animated_mesh]
|
||||
name = "Animated Mesh"
|
||||
description = "Plays an animation on a skinned glTF model of a fox"
|
||||
category = "Animation"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "animated_mesh_control"
|
||||
path = "examples/animation/animated_mesh_control.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.animated_mesh_control]
|
||||
name = "Animated Mesh Control"
|
||||
description = "Plays an animation from a skinned glTF with keyboard controls"
|
||||
category = "Animation"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "animated_mesh_events"
|
||||
path = "examples/animation/animated_mesh_events.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.animated_mesh_events]
|
||||
name = "Animated Mesh Events"
|
||||
description = "Plays an animation from a skinned glTF with events"
|
||||
category = "Animation"
|
||||
wasm = true
|
||||
|
||||
@ -3293,6 +3337,18 @@ description = "Creates a solid color window"
|
||||
category = "Window"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "custom_cursor_image"
|
||||
path = "examples/window/custom_cursor_image.rs"
|
||||
doc-scrape-examples = true
|
||||
required-features = ["custom_cursor"]
|
||||
|
||||
[package.metadata.example.custom_cursor_image]
|
||||
name = "Custom Cursor Image"
|
||||
description = "Demonstrates creating an animated custom cursor from an image"
|
||||
category = "Window"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "custom_user_event"
|
||||
path = "examples/window/custom_user_event.rs"
|
||||
@ -3855,6 +3911,18 @@ category = "Picking"
|
||||
wasm = true
|
||||
required-features = ["bevy_sprite_picking_backend"]
|
||||
|
||||
[[example]]
|
||||
name = "debug_picking"
|
||||
path = "examples/picking/debug_picking.rs"
|
||||
doc-scrape-examples = true
|
||||
required-features = ["bevy_dev_tools"]
|
||||
|
||||
[package.metadata.example.debug_picking]
|
||||
name = "Picking Debug Tools"
|
||||
description = "Demonstrates picking debug overlay"
|
||||
category = "Picking"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "animation_masks"
|
||||
path = "examples/animation/animation_masks.rs"
|
||||
@ -3984,6 +4052,17 @@ doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.tab_navigation]
|
||||
name = "Tab Navigation"
|
||||
description = "Demonstration of Tab Navigation"
|
||||
description = "Demonstration of Tab Navigation between UI elements"
|
||||
category = "UI (User Interface)"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "directional_navigation"
|
||||
path = "examples/ui/directional_navigation.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.directional_navigation]
|
||||
name = "Directional Navigation"
|
||||
description = "Demonstration of Directional Navigation between UI elements"
|
||||
category = "UI (User Interface)"
|
||||
wasm = true
|
||||
|
||||
19
assets/cursors/kenney_crosshairPack/License.txt
Normal file
19
assets/cursors/kenney_crosshairPack/License.txt
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
Crosshair Pack
|
||||
|
||||
by Kenney Vleugels (Kenney.nl)
|
||||
|
||||
------------------------------
|
||||
|
||||
License (Creative Commons Zero, CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
You may use these assets in personal and commercial projects.
|
||||
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
|
||||
|
||||
------------------------------
|
||||
|
||||
Donate: http://support.kenney.nl
|
||||
|
||||
Follow on Twitter for updates: @KenneyNL (www.twitter.com/kenneynl)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
2
assets/external/.gitignore
vendored
Normal file
2
assets/external/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@ -10,16 +10,24 @@
|
||||
|
||||
@fragment
|
||||
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
|
||||
// normalized position relative to the center of the UI node
|
||||
let r = in.uv - 0.5;
|
||||
|
||||
// normalized size of the border closest to the current position
|
||||
let b = vec2(
|
||||
select(in.border_widths.x, in.border_widths.y, r.x < 0.),
|
||||
select(in.border_widths.z, in.border_widths.w, r.y < 0.)
|
||||
select(in.border_widths.x, in.border_widths.y, 0. < r.x),
|
||||
select(in.border_widths.z, in.border_widths.w, 0. < r.y)
|
||||
);
|
||||
|
||||
// if the distance to the edge from the current position on any axis
|
||||
// is less than the border width on that axis then the position is within
|
||||
// the border and we return the border color
|
||||
if any(0.5 - b < abs(r)) {
|
||||
return border_color;
|
||||
}
|
||||
|
||||
// sample the texture at this position if it's to the left of the slider value
|
||||
// otherwise return a fully transparent color
|
||||
if in.uv.x < slider {
|
||||
let output_color = textureSample(material_color_texture, material_color_sampler, in.uv) * color;
|
||||
return output_color;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var<storage, read> colors: array<vec4<f32>, 5>;
|
||||
@group(2) @binding(1) var<uniform> color_id: u32;
|
||||
|
||||
struct Vertex {
|
||||
@builtin(instance_index) instance_index: u32,
|
||||
@ -23,10 +24,7 @@ fn vertex(vertex: Vertex) -> VertexOutput {
|
||||
out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4(vertex.position, 1.0));
|
||||
out.clip_position = position_world_to_clip(out.world_position.xyz);
|
||||
|
||||
// We have 5 colors in the storage buffer, but potentially many instances of the mesh, so
|
||||
// we use the instance index to select a color from the storage buffer.
|
||||
out.color = colors[vertex.instance_index % 5];
|
||||
|
||||
out.color = colors[color_id];
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,6 @@ criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||
# Bevy crates
|
||||
bevy_app = { path = "../crates/bevy_app" }
|
||||
bevy_ecs = { path = "../crates/bevy_ecs", features = ["multi_threaded"] }
|
||||
bevy_hierarchy = { path = "../crates/bevy_hierarchy" }
|
||||
bevy_math = { path = "../crates/bevy_math" }
|
||||
bevy_picking = { path = "../crates/bevy_picking", features = [
|
||||
"bevy_mesh_picking_backend",
|
||||
@ -47,6 +46,7 @@ type_complexity = "allow"
|
||||
undocumented_unsafe_blocks = "warn"
|
||||
unwrap_or_default = "warn"
|
||||
needless_lifetimes = "allow"
|
||||
too_many_arguments = "allow"
|
||||
|
||||
ptr_as_ptr = "warn"
|
||||
ptr_cast_constness = "warn"
|
||||
@ -55,11 +55,21 @@ ref_as_ptr = "warn"
|
||||
# see: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366966219
|
||||
too_long_first_doc_paragraph = "allow"
|
||||
|
||||
allow_attributes = "warn"
|
||||
allow_attributes_without_reason = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(docsrs_dep)'] }
|
||||
unsafe_op_in_unsafe_fn = "warn"
|
||||
unused_qualifications = "warn"
|
||||
|
||||
[lib]
|
||||
# This fixes the "Unrecognized Option" error when running commands like
|
||||
# `cargo bench -- --save-baseline before` by disabling the default benchmark harness.
|
||||
# See <https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options>
|
||||
# for more information.
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "ecs"
|
||||
path = "benches/bevy_ecs/main.rs"
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
#![allow(dead_code)]
|
||||
#![expect(
|
||||
dead_code,
|
||||
reason = "The `Mat4`s in the structs are used to bloat the size of the structs for benchmarking purposes."
|
||||
)]
|
||||
|
||||
use bevy_ecs::prelude::*;
|
||||
use glam::*;
|
||||
|
||||
@ -3,9 +3,9 @@ use core::hint::black_box;
|
||||
use benches::bench;
|
||||
use bevy_ecs::bundle::Bundle;
|
||||
use bevy_ecs::component::ComponentCloneHandler;
|
||||
use bevy_ecs::hierarchy::Parent;
|
||||
use bevy_ecs::reflect::AppTypeRegistry;
|
||||
use bevy_ecs::{component::Component, world::World};
|
||||
use bevy_hierarchy::{BuildChildren, CloneEntityHierarchyExt};
|
||||
use bevy_math::Mat4;
|
||||
use bevy_reflect::{GetTypeRegistration, Reflect};
|
||||
use criterion::{criterion_group, Bencher, Criterion, Throughput};
|
||||
@ -142,8 +142,7 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
|
||||
|
||||
for parent_id in current_hierarchy_level {
|
||||
for _ in 0..children {
|
||||
let child_id = world.spawn(B::default()).set_parent(parent_id).id();
|
||||
|
||||
let child_id = world.spawn((B::default(), Parent(parent_id))).id();
|
||||
hierarchy_level.push(child_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
dead_code,
|
||||
reason = "Many fields are unused/unread as they are just for benchmarking purposes."
|
||||
)]
|
||||
#![expect(clippy::type_complexity)]
|
||||
|
||||
use criterion::criterion_main;
|
||||
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
use core::hint::black_box;
|
||||
|
||||
use bevy_ecs::{
|
||||
component::Component, entity::Entity, event::Event, observer::Trigger, world::World,
|
||||
};
|
||||
use bevy_hierarchy::{BuildChildren, Parent};
|
||||
|
||||
use bevy_ecs::prelude::*;
|
||||
use criterion::Criterion;
|
||||
use rand::SeedableRng;
|
||||
use rand::{seq::IteratorRandom, Rng};
|
||||
|
||||
@ -2,8 +2,8 @@ use core::hint::black_box;
|
||||
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
system::Commands,
|
||||
world::{Command, CommandQueue, World},
|
||||
system::{Command, Commands},
|
||||
world::{CommandQueue, World},
|
||||
};
|
||||
use criterion::Criterion;
|
||||
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_hierarchy::despawn_with_children_recursive;
|
||||
use bevy_hierarchy::BuildChildren;
|
||||
use bevy_hierarchy::ChildBuild;
|
||||
use criterion::Criterion;
|
||||
use glam::*;
|
||||
|
||||
@ -29,7 +26,7 @@ pub fn world_despawn_recursive(criterion: &mut Criterion) {
|
||||
group.bench_function(format!("{}_entities", entity_count), |bencher| {
|
||||
bencher.iter(|| {
|
||||
ents.iter().for_each(|e| {
|
||||
despawn_with_children_recursive(&mut world, *e, true);
|
||||
world.entity_mut(*e).despawn();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -102,7 +102,6 @@ fn simple<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
|
||||
a + b
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn complex<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(
|
||||
_: T0,
|
||||
_: T1,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![expect(clippy::type_complexity)]
|
||||
|
||||
use criterion::criterion_main;
|
||||
|
||||
mod function;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_a11y"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides accessibility support for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -10,11 +10,11 @@ keywords = ["bevy", "accessibility", "a11y"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" }
|
||||
bevy_input_focus = { path = "../bevy_input_focus", version = "0.15.0-dev" }
|
||||
bevy_app = { path = "../bevy_app", 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_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
|
||||
bevy_input_focus = { path = "../bevy_input_focus", version = "0.16.0-dev" }
|
||||
|
||||
accesskit = "0.17"
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::allow_attributes, clippy::allow_attributes_without_reason)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc(
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_animation"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides animation functionality for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -10,35 +10,35 @@ keywords = ["bevy"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.15.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
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_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
"petgraph",
|
||||
] }
|
||||
bevy_render = { path = "../bevy_render", version = "0.15.0-dev" }
|
||||
bevy_time = { path = "../bevy_time", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
|
||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" }
|
||||
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" }
|
||||
|
||||
# other
|
||||
petgraph = { version = "0.6", features = ["serde-1"] }
|
||||
ron = "0.8"
|
||||
serde = "1"
|
||||
blake3 = { version = "1.0" }
|
||||
downcast-rs = "1.2.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"] }
|
||||
either = "1.13"
|
||||
thread_local = "1"
|
||||
uuid = { version = "1.7", features = ["v4"] }
|
||||
smallvec = "1"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -18,7 +18,7 @@ pub struct BlendInput<T> {
|
||||
|
||||
/// An animatable value type.
|
||||
pub trait Animatable: Reflect + Sized + Send + Sync + 'static {
|
||||
/// Interpolates between `a` and `b` with a interpolation factor of `time`.
|
||||
/// Interpolates between `a` and `b` with an interpolation factor of `time`.
|
||||
///
|
||||
/// The `time` parameter here may not be clamped to the range `[0.0, 1.0]`.
|
||||
fn interpolate(a: &Self, b: &Self, time: f32) -> Self;
|
||||
|
||||
@ -984,6 +984,7 @@ where
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_animation::{animation_curves::AnimatedField, animated_field};
|
||||
/// # use bevy_color::Srgba;
|
||||
/// # use bevy_ecs::component::Component;
|
||||
/// # use bevy_math::Vec3;
|
||||
/// # use bevy_reflect::Reflect;
|
||||
@ -993,10 +994,15 @@ where
|
||||
/// }
|
||||
///
|
||||
/// let field = animated_field!(Transform::translation);
|
||||
///
|
||||
/// #[derive(Component, Reflect)]
|
||||
/// struct Color(Srgba);
|
||||
///
|
||||
/// let tuple_field = animated_field!(Color::0);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! animated_field {
|
||||
($component:ident::$field:ident) => {
|
||||
($component:ident::$field:tt) => {
|
||||
AnimatedField::new_unchecked(stringify!($field), |component: &mut $component| {
|
||||
&mut component.$field
|
||||
})
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::allow_attributes, clippy::allow_attributes_without_reason)]
|
||||
#![doc(
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
@ -44,13 +43,11 @@ use bevy_math::FloatOrd;
|
||||
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
|
||||
use bevy_time::Time;
|
||||
use bevy_transform::TransformSystem;
|
||||
use bevy_utils::{
|
||||
tracing::{trace, warn},
|
||||
HashMap, NoOpHash, PreHashMap, PreHashMapExt, TypeIdMap,
|
||||
};
|
||||
use bevy_utils::{HashMap, NoOpHash, PreHashMap, PreHashMapExt, TypeIdMap};
|
||||
use petgraph::graph::NodeIndex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thread_local::ThreadLocal;
|
||||
use tracing::{trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// The animation prelude.
|
||||
@ -467,7 +464,7 @@ pub enum AnimationEvaluationError {
|
||||
/// An animation that an [`AnimationPlayer`] is currently either playing or was
|
||||
/// playing, but is presently paused.
|
||||
///
|
||||
/// An stopped animation is considered no longer active.
|
||||
/// A stopped animation is considered no longer active.
|
||||
#[derive(Debug, Clone, Copy, Reflect)]
|
||||
pub struct ActiveAnimation {
|
||||
/// The factor by which the weight from the [`AnimationGraph`] is multiplied.
|
||||
@ -939,13 +936,6 @@ impl AnimationPlayer {
|
||||
pub fn animation_mut(&mut self, animation: AnimationNodeIndex) -> Option<&mut ActiveAnimation> {
|
||||
self.active_animations.get_mut(&animation)
|
||||
}
|
||||
|
||||
#[deprecated = "Use `is_playing_animation` instead"]
|
||||
/// Returns true if the animation is currently playing or paused, or false
|
||||
/// if the animation is stopped.
|
||||
pub fn animation_is_playing(&self, animation: AnimationNodeIndex) -> bool {
|
||||
self.active_animations.contains_key(&animation)
|
||||
}
|
||||
}
|
||||
|
||||
/// A system that triggers untargeted animation events for the currently-playing animations.
|
||||
|
||||
@ -10,7 +10,7 @@ use bevy_ecs::{
|
||||
};
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_time::Time;
|
||||
use bevy_utils::Duration;
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::{graph::AnimationNodeIndex, ActiveAnimation, AnimationPlayer};
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_app"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides core App functionality for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
|
||||
keywords = ["bevy"]
|
||||
|
||||
[features]
|
||||
default = ["std", "bevy_reflect", "bevy_tasks", "bevy_ecs/default", "downcast"]
|
||||
default = ["std", "bevy_reflect", "bevy_tasks", "bevy_ecs/default"]
|
||||
|
||||
# Functionality
|
||||
|
||||
@ -31,9 +31,6 @@ reflect_auto_register = [
|
||||
## Adds support for running async background tasks
|
||||
bevy_tasks = ["dep:bevy_tasks"]
|
||||
|
||||
## Adds `downcast-rs` integration for `Plugin`
|
||||
downcast = ["dep:downcast-rs"]
|
||||
|
||||
# Debugging Features
|
||||
|
||||
## Enables `tracing` integration, allowing spans and other metrics to be reported
|
||||
@ -53,7 +50,7 @@ std = [
|
||||
"bevy_reflect?/std",
|
||||
"bevy_ecs/std",
|
||||
"dep:ctrlc",
|
||||
"downcast-rs?/std",
|
||||
"downcast-rs/std",
|
||||
"bevy_utils/std",
|
||||
"bevy_tasks?/std",
|
||||
]
|
||||
@ -77,16 +74,16 @@ portable-atomic = [
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", default-features = false, optional = true }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev", default-features = false, features = [
|
||||
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, features = [
|
||||
"alloc",
|
||||
] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev", default-features = false, optional = true }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false, optional = true }
|
||||
|
||||
# other
|
||||
downcast-rs = { version = "1.2.0", default-features = false, optional = true }
|
||||
downcast-rs = { version = "2", default-features = false }
|
||||
thiserror = { version = "2", default-features = false }
|
||||
variadics_please = "1.1"
|
||||
tracing = { version = "0.1", default-features = false, optional = true }
|
||||
@ -98,7 +95,7 @@ portable-atomic-util = { version = "0.2.4", features = [
|
||||
"alloc",
|
||||
], optional = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
[target.'cfg(any(unix, windows))'.dependencies]
|
||||
ctrlc = { version = "3.4.4", optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::{
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
pub use bevy_derive::AppLabel;
|
||||
use bevy_ecs::{
|
||||
@ -29,9 +30,6 @@ use std::{
|
||||
process::{ExitCode, Termination},
|
||||
};
|
||||
|
||||
#[cfg(feature = "downcast")]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
bevy_ecs::define_label!(
|
||||
/// A strongly-typed class of labels used to identify an [`App`].
|
||||
AppLabel,
|
||||
@ -111,6 +109,8 @@ impl Default for App {
|
||||
app.insert_resource(AppTypeRegistry::new_with_derived_types());
|
||||
|
||||
app.register_type::<Name>();
|
||||
app.register_type::<Parent>();
|
||||
app.register_type::<Children>();
|
||||
}
|
||||
|
||||
#[cfg(feature = "reflect_functions")]
|
||||
@ -527,7 +527,6 @@ impl App {
|
||||
/// # app.add_plugins(ImagePlugin::default());
|
||||
/// let default_sampler = app.get_added_plugins::<ImagePlugin>()[0].default_sampler;
|
||||
/// ```
|
||||
#[cfg(feature = "downcast")]
|
||||
pub fn get_added_plugins<T>(&self) -> Vec<&T>
|
||||
where
|
||||
T: Plugin,
|
||||
@ -1365,7 +1364,7 @@ pub enum AppExit {
|
||||
}
|
||||
|
||||
impl AppExit {
|
||||
/// Creates a [`AppExit::Error`] with a error code of 1.
|
||||
/// Creates a [`AppExit::Error`] with an error code of 1.
|
||||
#[must_use]
|
||||
pub const fn error() -> Self {
|
||||
Self::Error(NonZero::<u8>::MIN)
|
||||
@ -1741,7 +1740,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn app_exit_size() {
|
||||
// There wont be many of them so the size isn't a issue but
|
||||
// There wont be many of them so the size isn't an issue but
|
||||
// it's nice they're so small let's keep it that way.
|
||||
assert_eq!(size_of::<AppExit>(), size_of::<u8>());
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
)]
|
||||
#![cfg_attr(any(docsrs, docsrs_dep), feature(doc_auto_cfg, rustdoc_internals))]
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::allow_attributes, clippy::allow_attributes_without_reason)]
|
||||
#![doc(
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
@ -30,7 +29,7 @@ mod schedule_runner;
|
||||
mod sub_app;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
mod task_pool_plugin;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
|
||||
#[cfg(all(any(unix, windows), feature = "std"))]
|
||||
mod terminal_ctrl_c_handler;
|
||||
|
||||
pub use app::*;
|
||||
@ -42,7 +41,7 @@ pub use schedule_runner::*;
|
||||
pub use sub_app::*;
|
||||
#[cfg(feature = "bevy_tasks")]
|
||||
pub use task_pool_plugin::*;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
|
||||
#[cfg(all(any(unix, windows), feature = "std"))]
|
||||
pub use terminal_ctrl_c_handler::*;
|
||||
|
||||
/// The app prelude.
|
||||
|
||||
@ -1,20 +1,6 @@
|
||||
// TODO: Upstream `portable-atomic` support to `downcast_rs` and unconditionally
|
||||
// include it as a dependency.
|
||||
// See https://github.com/marcianx/downcast-rs/pull/22 for details
|
||||
#[cfg(feature = "downcast")]
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
|
||||
use crate::App;
|
||||
use core::any::Any;
|
||||
|
||||
/// Dummy trait with the same name as `downcast_rs::Downcast`. This is to ensure
|
||||
/// the `Plugin: Downcast` bound can remain even when `downcast` isn't enabled.
|
||||
#[cfg(not(feature = "downcast"))]
|
||||
#[doc(hidden)]
|
||||
pub trait Downcast {}
|
||||
|
||||
#[cfg(not(feature = "downcast"))]
|
||||
impl<T: ?Sized> Downcast for T {}
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
|
||||
/// A collection of Bevy app logic and configuration.
|
||||
///
|
||||
@ -105,7 +91,6 @@ pub trait Plugin: Downcast + Any + Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "downcast")]
|
||||
impl_downcast!(Plugin);
|
||||
|
||||
impl<T: Fn(&mut App) + Send + Sync + 'static> Plugin for T {
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::{
|
||||
plugin::Plugin,
|
||||
PluginsState,
|
||||
};
|
||||
use bevy_utils::Duration;
|
||||
use core::time::Duration;
|
||||
|
||||
#[cfg(any(target_arch = "wasm32", feature = "std"))]
|
||||
use bevy_utils::Instant;
|
||||
|
||||
@ -362,7 +362,6 @@ impl SubApp {
|
||||
}
|
||||
|
||||
/// See [`App::get_added_plugins`].
|
||||
#[cfg(feature = "downcast")]
|
||||
pub fn get_added_plugins<T>(&self) -> Vec<&T>
|
||||
where
|
||||
T: Plugin,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_asset"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides asset functionality for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -19,14 +19,14 @@ watch = []
|
||||
trace = []
|
||||
|
||||
[dependencies]
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset_macros = { path = "macros", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
||||
bevy_asset_macros = { path = "macros", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"uuid",
|
||||
] }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
|
||||
|
||||
stackfuture = "0.3"
|
||||
atomicow = "1.0"
|
||||
@ -35,7 +35,7 @@ async-fs = "2.0"
|
||||
async-lock = "3.0"
|
||||
bitflags = { version = "2.3", features = ["serde"] }
|
||||
crossbeam-channel = "0.5"
|
||||
downcast-rs = "1.2"
|
||||
downcast-rs = { version = "2", default-features = false, features = ["std"] }
|
||||
disqualified = "1.0"
|
||||
either = "1.13"
|
||||
futures-io = "0.3"
|
||||
@ -47,9 +47,10 @@ serde = { version = "1", features = ["derive"] }
|
||||
thiserror = { version = "2", default-features = false }
|
||||
derive_more = { version = "1", default-features = false, features = ["from"] }
|
||||
uuid = { version = "1.0", features = ["v4"] }
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
bevy_window = { path = "../bevy_window", version = "0.15.0-dev" }
|
||||
bevy_window = { path = "../bevy_window", version = "0.16.0-dev" }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
@ -65,7 +66,7 @@ js-sys = "0.3"
|
||||
notify-debouncer-full = { version = "0.4.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bevy_log = { path = "../bevy_log", version = "0.15.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_asset_macros"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Derive implementations for bevy_asset"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -12,7 +12,7 @@ keywords = ["bevy"]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.15.0-dev" }
|
||||
bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.16.0-dev" }
|
||||
|
||||
syn = "2.0"
|
||||
proc-macro2 = "1.0"
|
||||
|
||||
@ -13,10 +13,10 @@ use bevy_ecs::{
|
||||
storage::{Table, TableRow},
|
||||
world::unsafe_world_cell::UnsafeWorldCell,
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use bevy_utils::HashMap;
|
||||
use core::marker::PhantomData;
|
||||
use disqualified::ShortName;
|
||||
use tracing::error;
|
||||
|
||||
/// A resource that stores the last tick an asset was changed. This is used by
|
||||
/// the [`AssetChanged`] filter to determine if an asset has changed since the last time
|
||||
@ -86,7 +86,7 @@ impl<'w, A: AsAssetId> AssetChangeCheck<'w, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter that selects entities with a `A` for an asset that changed
|
||||
/// Filter that selects entities with an `A` for an asset that changed
|
||||
/// after the system last ran, where `A` is a component that implements
|
||||
/// [`AsAssetId`].
|
||||
///
|
||||
@ -114,8 +114,8 @@ impl<'w, A: AsAssetId> AssetChangeCheck<'w, A> {
|
||||
/// # Performance
|
||||
///
|
||||
/// When at least one `A` is updated, this will
|
||||
/// read a hashmap once per entity with a `A` component. The
|
||||
/// runtime of the query is proportional to how many entities with a `A`
|
||||
/// read a hashmap once per entity with an `A` component. The
|
||||
/// runtime of the query is proportional to how many entities with an `A`
|
||||
/// it matches.
|
||||
///
|
||||
/// If no `A` asset updated since the last time the system ran, then no lookups occur.
|
||||
@ -148,7 +148,7 @@ pub struct AssetChangedState<A: AsAssetId> {
|
||||
_asset: PhantomData<fn(A)>,
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
#[expect(unsafe_code, reason = "WorldQuery is an unsafe trait.")]
|
||||
/// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||
unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
||||
type Item<'w> = ();
|
||||
@ -233,11 +233,6 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
||||
#[inline]
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
<&A>::update_component_access(&state.asset_id, access);
|
||||
assert!(
|
||||
!access.access().has_resource_write(state.resource_id),
|
||||
"AssetChanged<{ty}> requires read-only access to AssetChanges<{ty}>",
|
||||
ty = ShortName::of::<A>()
|
||||
);
|
||||
access.add_resource_read(state.resource_id);
|
||||
}
|
||||
|
||||
@ -269,7 +264,7 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
#[expect(unsafe_code, reason = "QueryFilter is an unsafe trait.")]
|
||||
/// SAFETY: read-only access
|
||||
unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
|
||||
const IS_ARCHETYPAL: bool = false;
|
||||
@ -293,7 +288,9 @@ unsafe impl<A: AsAssetId> QueryFilter for AssetChanged<A> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{self as bevy_asset, AssetEvents, AssetPlugin, Handle};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::num::NonZero;
|
||||
use std::println;
|
||||
|
||||
use crate::{AssetApp, Assets};
|
||||
use bevy_app::{App, AppExit, Last, Startup, TaskPoolPlugin, Update};
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::{
|
||||
self as bevy_asset, Asset, AssetEvent, AssetHandleProvider, AssetId, AssetServer, Handle,
|
||||
UntypedHandle,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use bevy_ecs::{
|
||||
prelude::EventWriter,
|
||||
system::{Res, ResMut, Resource, SystemChangeTick},
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate as bevy_asset;
|
||||
use crate::{Asset, UntypedHandle};
|
||||
use bevy_reflect::TypePath;
|
||||
|
||||
@ -514,6 +514,7 @@ pub enum UntypedAssetConversionError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::boxed::Box;
|
||||
use bevy_reflect::PartialReflect;
|
||||
use bevy_utils::FixedHasher;
|
||||
use core::hash::BuildHasher;
|
||||
@ -551,8 +552,11 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Typed and Untyped `Handles` should be orderable amongst each other and themselves
|
||||
#[allow(clippy::cmp_owned)]
|
||||
#[test]
|
||||
#[expect(
|
||||
clippy::cmp_owned,
|
||||
reason = "This lints on the assertion that a typed handle converted to an untyped handle maintains its ordering compared to an untyped handle. While the conversion would normally be useless, we need to ensure that converted handles maintain their ordering, making the conversion necessary here."
|
||||
)]
|
||||
fn ordering() {
|
||||
assert!(UUID_1 < UUID_2);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::io::{get_meta_path, AssetReader, AssetReaderError, PathStream, Reader, VecReader};
|
||||
use bevy_utils::tracing::error;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, ffi::CString, vec::Vec};
|
||||
use futures_lite::stream;
|
||||
use std::{ffi::CString, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
/// [`AssetReader`] implementation for Android devices, built on top of Android's [`AssetManager`].
|
||||
///
|
||||
@ -72,10 +72,7 @@ impl AssetReader for AndroidAssetReader {
|
||||
Ok(read_dir)
|
||||
}
|
||||
|
||||
async fn is_directory<'a>(
|
||||
&'a self,
|
||||
path: &'a Path,
|
||||
) -> std::result::Result<bool, AssetReaderError> {
|
||||
async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {
|
||||
let asset_manager = bevy_window::ANDROID_APP
|
||||
.get()
|
||||
.expect("Bevy must be setup with the #[bevy_main] macro on Android")
|
||||
|
||||
@ -3,8 +3,9 @@ use crate::io::{
|
||||
memory::Dir,
|
||||
AssetSourceEvent, AssetWatcher,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use bevy_utils::{tracing::warn, Duration, HashMap};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use bevy_utils::HashMap;
|
||||
use core::time::Duration;
|
||||
use notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, RecommendedCache};
|
||||
use parking_lot::RwLock;
|
||||
use std::{
|
||||
@ -12,6 +13,7 @@ use std::{
|
||||
io::{BufReader, Read},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tracing::warn;
|
||||
|
||||
/// A watcher for assets stored in the `embedded` asset source. Embedded assets are assets whose
|
||||
/// bytes have been embedded into the Rust binary using the [`embedded_asset`](crate::embedded_asset) macro.
|
||||
|
||||
@ -8,9 +8,13 @@ use crate::io::{
|
||||
memory::{Dir, MemoryAssetReader, Value},
|
||||
AssetSource, AssetSourceBuilders,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use bevy_ecs::system::Resource;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(feature = "embedded_watcher")]
|
||||
use alloc::borrow::ToOwned;
|
||||
|
||||
pub const EMBEDDED: &str = "embedded";
|
||||
|
||||
/// A [`Resource`] that manages "rust source files" in a virtual in memory [`Dir`], which is intended
|
||||
@ -29,7 +33,7 @@ impl EmbeddedAssetRegistry {
|
||||
/// Inserts a new asset. `full_path` is the full path (as [`file`] would return for that file, if it was capable of
|
||||
/// running in a non-rust file). `asset_path` is the path that will be used to identify the asset in the `embedded`
|
||||
/// [`AssetSource`]. `value` is the bytes that will be returned for the asset. This can be _either_ a `&'static [u8]`
|
||||
/// or a [`Vec<u8>`].
|
||||
/// or a [`Vec<u8>`](alloc::vec::Vec).
|
||||
#[cfg_attr(
|
||||
not(feature = "embedded_watcher"),
|
||||
expect(
|
||||
@ -48,7 +52,7 @@ impl EmbeddedAssetRegistry {
|
||||
/// Inserts new asset metadata. `full_path` is the full path (as [`file`] would return for that file, if it was capable of
|
||||
/// running in a non-rust file). `asset_path` is the path that will be used to identify the asset in the `embedded`
|
||||
/// [`AssetSource`]. `value` is the bytes that will be returned for the asset. This can be _either_ a `&'static [u8]`
|
||||
/// or a [`Vec<u8>`].
|
||||
/// or a [`Vec<u8>`](alloc::vec::Vec).
|
||||
#[cfg_attr(
|
||||
not(feature = "embedded_watcher"),
|
||||
expect(
|
||||
|
||||
@ -6,6 +6,7 @@ use async_fs::{read_dir, File};
|
||||
use futures_io::AsyncSeek;
|
||||
use futures_lite::StreamExt;
|
||||
|
||||
use alloc::{borrow::ToOwned, boxed::Box};
|
||||
use core::{pin::Pin, task, task::Poll};
|
||||
use std::path::Path;
|
||||
|
||||
|
||||
@ -2,7 +2,8 @@ use crate::{
|
||||
io::{AssetSourceEvent, AssetWatcher},
|
||||
path::normalize_path,
|
||||
};
|
||||
use bevy_utils::{tracing::error, Duration};
|
||||
use alloc::borrow::ToOwned;
|
||||
use core::time::Duration;
|
||||
use crossbeam_channel::Sender;
|
||||
use notify_debouncer_full::{
|
||||
new_debouncer,
|
||||
@ -14,6 +15,7 @@ use notify_debouncer_full::{
|
||||
DebounceEventResult, Debouncer, RecommendedCache,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tracing::error;
|
||||
|
||||
/// An [`AssetWatcher`] that watches the filesystem for changes to asset files in a given root folder and emits [`AssetSourceEvent`]
|
||||
/// for each relevant change. This uses [`notify_debouncer_full`] to retrieve "debounced" filesystem events.
|
||||
|
||||
@ -6,10 +6,11 @@ mod file_asset;
|
||||
#[cfg(not(feature = "multi_threaded"))]
|
||||
mod sync_file_asset;
|
||||
|
||||
use bevy_utils::tracing::{debug, error};
|
||||
#[cfg(feature = "file_watcher")]
|
||||
pub use file_watcher::*;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use std::{
|
||||
env,
|
||||
path::{Path, PathBuf},
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::io::{
|
||||
PathStream, Reader, Writer,
|
||||
};
|
||||
|
||||
use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
|
||||
use core::{pin::Pin, task::Poll};
|
||||
use std::{
|
||||
fs::{read_dir, File},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::io::{AssetReader, AssetReaderError, PathStream, Reader};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use bevy_utils::HashMap;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::io::{AssetReader, AssetReaderError, PathStream, Reader};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec::Vec};
|
||||
use bevy_utils::HashMap;
|
||||
use core::{pin::Pin, task::Poll};
|
||||
use futures_io::AsyncRead;
|
||||
|
||||
@ -21,7 +21,7 @@ mod source;
|
||||
pub use futures_lite::AsyncWriteExt;
|
||||
pub use source::*;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use bevy_tasks::{BoxedFuture, ConditionalSendFuture};
|
||||
use core::future::Future;
|
||||
use core::{
|
||||
|
||||
@ -3,12 +3,12 @@ use crate::{
|
||||
processor::{AssetProcessorData, ProcessStatus},
|
||||
AssetPath,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec::Vec};
|
||||
use async_lock::RwLockReadGuardArc;
|
||||
use bevy_utils::tracing::trace;
|
||||
use core::{pin::Pin, task::Poll};
|
||||
use futures_io::AsyncRead;
|
||||
use std::path::Path;
|
||||
use tracing::trace;
|
||||
|
||||
use super::{AsyncSeekForward, ErasedAssetReader};
|
||||
|
||||
|
||||
@ -2,15 +2,17 @@ use crate::{
|
||||
io::{processor_gated::ProcessorGatedReader, AssetSourceEvent, AssetWatcher},
|
||||
processor::AssetProcessorData,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
};
|
||||
use atomicow::CowArc;
|
||||
use bevy_ecs::system::Resource;
|
||||
use bevy_utils::{
|
||||
tracing::{error, warn},
|
||||
Duration, HashMap,
|
||||
};
|
||||
use core::{fmt::Display, hash::Hash};
|
||||
use bevy_utils::HashMap;
|
||||
use core::{fmt::Display, hash::Hash, time::Duration};
|
||||
use thiserror::Error;
|
||||
use tracing::{error, warn};
|
||||
|
||||
use super::{ErasedAssetReader, ErasedAssetWriter};
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use crate::io::{
|
||||
get_meta_path, AssetReader, AssetReaderError, EmptyPathStream, PathStream, Reader, VecReader,
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, format};
|
||||
use js_sys::{Uint8Array, JSON};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tracing::error;
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::Response;
|
||||
|
||||
@ -144,9 +144,10 @@
|
||||
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
||||
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
||||
)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate core;
|
||||
extern crate std;
|
||||
|
||||
pub mod io;
|
||||
pub mod meta;
|
||||
@ -206,7 +207,11 @@ use crate::{
|
||||
io::{embedded::EmbeddedAssetRegistry, AssetSourceBuilder, AssetSourceBuilders, AssetSourceId},
|
||||
processor::{AssetProcessor, Process},
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use bevy_app::{App, Last, Plugin, PreUpdate};
|
||||
use bevy_ecs::prelude::Component;
|
||||
use bevy_ecs::{
|
||||
@ -215,8 +220,9 @@ use bevy_ecs::{
|
||||
world::FromWorld,
|
||||
};
|
||||
use bevy_reflect::{FromReflect, GetTypeRegistration, Reflect, TypePath};
|
||||
use bevy_utils::{tracing::error, HashSet};
|
||||
use bevy_utils::HashSet;
|
||||
use core::any::TypeId;
|
||||
use tracing::error;
|
||||
|
||||
#[cfg(all(feature = "file_watcher", not(feature = "multi_threaded")))]
|
||||
compile_error!(
|
||||
@ -632,7 +638,14 @@ mod tests {
|
||||
Asset, AssetApp, AssetEvent, AssetId, AssetLoadError, AssetLoadFailedEvent, AssetPath,
|
||||
AssetPlugin, AssetServer, Assets,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use bevy_app::{App, TaskPoolPlugin, Update};
|
||||
use bevy_ecs::{
|
||||
event::EventCursor,
|
||||
@ -641,7 +654,8 @@ mod tests {
|
||||
};
|
||||
use bevy_log::LogPlugin;
|
||||
use bevy_reflect::TypePath;
|
||||
use bevy_utils::{Duration, HashMap};
|
||||
use bevy_utils::HashMap;
|
||||
use core::time::Duration;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use thiserror::Error;
|
||||
@ -1765,8 +1779,11 @@ mod tests {
|
||||
#[derive(Asset, TypePath)]
|
||||
pub struct TestAsset;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath)]
|
||||
#[expect(
|
||||
dead_code,
|
||||
reason = "This exists to ensure that `#[derive(Asset)]` works on enums. The inner variants are known not to be used."
|
||||
)]
|
||||
pub enum EnumTestAsset {
|
||||
Unnamed(#[dependency] Handle<TestAsset>),
|
||||
Named {
|
||||
@ -1781,7 +1798,6 @@ mod tests {
|
||||
Empty,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath)]
|
||||
pub struct StructTestAsset {
|
||||
#[dependency]
|
||||
@ -1790,7 +1806,6 @@ mod tests {
|
||||
embedded: TestAsset,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath)]
|
||||
pub struct TupleTestAsset(#[dependency] Handle<TestAsset>);
|
||||
}
|
||||
|
||||
@ -6,6 +6,11 @@ use crate::{
|
||||
Asset, AssetLoadError, AssetServer, AssetServerMode, Assets, Handle, UntypedAssetId,
|
||||
UntypedHandle,
|
||||
};
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use atomicow::CowArc;
|
||||
use bevy_ecs::world::World;
|
||||
use bevy_tasks::{BoxedFuture, ConditionalSendFuture};
|
||||
|
||||
@ -7,7 +7,7 @@ use crate::{
|
||||
Asset, AssetLoadError, AssetPath, ErasedAssetLoader, ErasedLoadedAsset, Handle, LoadContext,
|
||||
LoadDirectError, LoadedAsset, LoadedUntypedAsset, UntypedHandle,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc};
|
||||
use core::any::TypeId;
|
||||
|
||||
// Utility type for handling the sources of reader references
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
self as bevy_asset, loader::AssetLoader, processor::Process, Asset, AssetPath,
|
||||
DeserializeMetaError, VisitAssetDependencies,
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
use ron::ser::PrettyConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::error;
|
||||
|
||||
pub const META_FORMAT_VERSION: &str = "1.0";
|
||||
pub type MetaTransform = Box<dyn Fn(&mut dyn AssetMetaDyn) + Send + Sync>;
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
use crate::io::AssetSourceId;
|
||||
use alloc::{
|
||||
borrow::ToOwned,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use atomicow::CowArc;
|
||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
use core::{
|
||||
@ -316,7 +320,7 @@ impl<'a> AssetPath<'a> {
|
||||
/// If internally a value is a static reference, the static reference will be used unchanged.
|
||||
/// If internally a value is an "owned [`Arc`]", it will remain unchanged.
|
||||
///
|
||||
/// [`Arc`]: std::sync::Arc
|
||||
/// [`Arc`]: alloc::sync::Arc
|
||||
pub fn into_owned(self) -> AssetPath<'static> {
|
||||
AssetPath {
|
||||
source: self.source.into_owned(),
|
||||
@ -329,7 +333,7 @@ impl<'a> AssetPath<'a> {
|
||||
/// If internally a value is a static reference, the static reference will be used unchanged.
|
||||
/// If internally a value is an "owned [`Arc`]", the [`Arc`] will be cloned.
|
||||
///
|
||||
/// [`Arc`]: std::sync::Arc
|
||||
/// [`Arc`]: alloc::sync::Arc
|
||||
#[inline]
|
||||
pub fn clone_owned(&self) -> AssetPath<'static> {
|
||||
self.clone().into_owned()
|
||||
@ -629,6 +633,7 @@ pub(crate) fn normalize_path(path: &Path) -> PathBuf {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::AssetPath;
|
||||
use alloc::string::ToString;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
use crate::AssetPath;
|
||||
use alloc::{
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use async_fs::File;
|
||||
use bevy_utils::{tracing::error, HashSet};
|
||||
use bevy_utils::HashSet;
|
||||
use futures_lite::{AsyncReadExt, AsyncWriteExt};
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
use tracing::error;
|
||||
|
||||
/// An in-memory representation of a single [`ProcessorTransactionLog`] entry.
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -56,22 +56,23 @@ use crate::{
|
||||
AssetLoadError, AssetMetaCheck, AssetPath, AssetServer, AssetServerMode, DeserializeMetaError,
|
||||
MissingAssetLoaderForExtensionError,
|
||||
};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, collections::VecDeque, sync::Arc, vec, vec::Vec};
|
||||
use bevy_ecs::prelude::*;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_tasks::ConditionalSendFuture;
|
||||
use bevy_tasks::IoTaskPool;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::{info_span, instrument::Instrument};
|
||||
use bevy_utils::{
|
||||
tracing::{debug, error, trace, warn},
|
||||
HashMap, HashSet,
|
||||
};
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
use futures_io::ErrorKind;
|
||||
use futures_lite::{AsyncReadExt, AsyncWriteExt, StreamExt};
|
||||
use parking_lot::RwLock;
|
||||
use std::path::{Path, PathBuf};
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, trace, warn};
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
use {
|
||||
alloc::string::ToString,
|
||||
bevy_tasks::ConditionalSendFuture,
|
||||
tracing::{info_span, instrument::Instrument},
|
||||
};
|
||||
|
||||
/// A "background" asset processor that reads asset values from a source [`AssetSource`] (which corresponds to an [`AssetReader`](crate::io::AssetReader) / [`AssetWriter`](crate::io::AssetWriter) pair),
|
||||
/// processes them in some way, and writes them to a destination [`AssetSource`].
|
||||
@ -480,7 +481,6 @@ impl AssetProcessor {
|
||||
self.set_state(ProcessorState::Finished).await;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))]
|
||||
async fn process_assets_internal<'scope>(
|
||||
&'scope self,
|
||||
|
||||
@ -10,6 +10,11 @@ use crate::{
|
||||
AssetLoadError, AssetLoader, AssetPath, DeserializeMetaError, ErasedLoadedAsset,
|
||||
MissingAssetLoaderForExtensionError, MissingAssetLoaderForTypeNameError,
|
||||
};
|
||||
use alloc::{
|
||||
borrow::ToOwned,
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use bevy_tasks::{BoxedFuture, ConditionalSendFuture};
|
||||
use core::marker::PhantomData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -105,26 +110,6 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
/// A flexible [`Process`] implementation that loads the source [`Asset`] using the `L` [`AssetLoader`], then
|
||||
/// saves that `L` asset using the `S` [`AssetSaver`].
|
||||
///
|
||||
/// This is a specialized use case of [`LoadTransformAndSave`] and is useful where there is no asset manipulation
|
||||
/// such as when compressing assets.
|
||||
///
|
||||
/// This uses [`LoadAndSaveSettings`] to configure the processor.
|
||||
///
|
||||
/// [`Asset`]: crate::Asset
|
||||
#[deprecated = "Use `LoadTransformAndSave<L, IdentityAssetTransformer<<L as AssetLoader>::Asset>, S>` instead"]
|
||||
pub type LoadAndSave<L, S> =
|
||||
LoadTransformAndSave<L, IdentityAssetTransformer<<L as AssetLoader>::Asset>, S>;
|
||||
|
||||
/// Settings for the [`LoadAndSave`] [`Process::Settings`] implementation.
|
||||
///
|
||||
/// `LoaderSettings` corresponds to [`AssetLoader::Settings`] and `SaverSettings` corresponds to [`AssetSaver::Settings`].
|
||||
#[deprecated = "Use `LoadTransformAndSaveSettings<LoaderSettings, (), SaverSettings>` instead"]
|
||||
pub type LoadAndSaveSettings<LoaderSettings, SaverSettings> =
|
||||
LoadTransformAndSaveSettings<LoaderSettings, (), SaverSettings>;
|
||||
|
||||
/// An error that is encountered during [`Process::process`].
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ProcessError {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::any::{Any, TypeId};
|
||||
|
||||
use bevy_ecs::world::{unsafe_world_cell::UnsafeWorldCell, World};
|
||||
@ -243,6 +244,7 @@ impl<A: Asset> FromType<Handle<A>> for ReflectHandle {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::any::TypeId;
|
||||
|
||||
use crate as bevy_asset;
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::{
|
||||
io::Writer, meta::Settings, transformer::TransformedAsset, Asset, AssetLoader,
|
||||
ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use atomicow::CowArc;
|
||||
use bevy_tasks::{BoxedFuture, ConditionalSendFuture};
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
@ -4,14 +4,20 @@ use crate::{
|
||||
Handle, InternalAssetEvent, LoadState, RecursiveDependencyLoadState, StrongHandle,
|
||||
UntypedAssetId, UntypedHandle,
|
||||
};
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::{
|
||||
borrow::ToOwned,
|
||||
boxed::Box,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use bevy_ecs::world::World;
|
||||
use bevy_tasks::Task;
|
||||
use bevy_utils::{tracing::warn, Entry, HashMap, HashSet, TypeIdMap};
|
||||
use bevy_utils::{Entry, HashMap, HashSet, TypeIdMap};
|
||||
use core::{any::TypeId, task::Waker};
|
||||
use crossbeam_channel::Sender;
|
||||
use either::Either;
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct AssetInfo {
|
||||
@ -112,10 +118,6 @@ impl AssetInfos {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::too_many_arguments,
|
||||
reason = "Arguments needed so that both `create_loading_handle_untyped()` and `get_or_create_path_handle_internal()` may share code."
|
||||
)]
|
||||
fn create_handle_internal(
|
||||
infos: &mut HashMap<UntypedAssetId, AssetInfo>,
|
||||
handle_providers: &TypeIdMap<AssetHandleProvider>,
|
||||
|
||||
@ -2,16 +2,20 @@ use crate::{
|
||||
loader::{AssetLoader, ErasedAssetLoader},
|
||||
path::AssetPath,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use async_broadcast::RecvError;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_tasks::ConditionalSendFuture;
|
||||
use bevy_tasks::IoTaskPool;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::{info_span, instrument::Instrument};
|
||||
use bevy_utils::{tracing::warn, HashMap, TypeIdMap};
|
||||
use bevy_utils::{HashMap, TypeIdMap};
|
||||
use core::any::TypeId;
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
use {
|
||||
alloc::string::ToString,
|
||||
bevy_tasks::ConditionalSendFuture,
|
||||
tracing::{info_span, instrument::Instrument},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AssetLoaders {
|
||||
@ -46,6 +50,7 @@ impl AssetLoaders {
|
||||
};
|
||||
|
||||
if is_new {
|
||||
let existing_loaders_for_type_id = self.type_id_to_loaders.get(&loader_asset_type);
|
||||
let mut duplicate_extensions = Vec::new();
|
||||
for extension in AssetLoader::extensions(&*loader) {
|
||||
let list = self
|
||||
@ -54,26 +59,29 @@ impl AssetLoaders {
|
||||
.or_default();
|
||||
|
||||
if !list.is_empty() {
|
||||
duplicate_extensions.push(extension);
|
||||
if let Some(existing_loaders_for_type_id) = existing_loaders_for_type_id {
|
||||
if list
|
||||
.iter()
|
||||
.any(|index| existing_loaders_for_type_id.contains(index))
|
||||
{
|
||||
duplicate_extensions.push(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.push(loader_index);
|
||||
}
|
||||
|
||||
self.type_name_to_loader.insert(type_name, loader_index);
|
||||
|
||||
let list = self
|
||||
.type_id_to_loaders
|
||||
.entry(loader_asset_type)
|
||||
.or_default();
|
||||
|
||||
let duplicate_asset_registration = !list.is_empty();
|
||||
if !duplicate_extensions.is_empty() && duplicate_asset_registration {
|
||||
if !duplicate_extensions.is_empty() {
|
||||
warn!("Duplicate AssetLoader registered for Asset type `{loader_asset_type_name}` with extensions `{duplicate_extensions:?}`. \
|
||||
Loader must be specified in a .meta file in order to load assets of this type with these extensions.");
|
||||
}
|
||||
|
||||
list.push(loader_index);
|
||||
self.type_name_to_loader.insert(type_name, loader_index);
|
||||
|
||||
self.type_id_to_loaders
|
||||
.entry(loader_asset_type)
|
||||
.or_default()
|
||||
.push(loader_index);
|
||||
|
||||
self.loaders.push(MaybeAssetLoader::Ready(loader));
|
||||
} else {
|
||||
@ -107,6 +115,8 @@ impl AssetLoaders {
|
||||
|
||||
self.preregistered_loaders.insert(type_name, loader_index);
|
||||
self.type_name_to_loader.insert(type_name, loader_index);
|
||||
|
||||
let existing_loaders_for_type_id = self.type_id_to_loaders.get(&loader_asset_type);
|
||||
let mut duplicate_extensions = Vec::new();
|
||||
for extension in extensions {
|
||||
let list = self
|
||||
@ -115,24 +125,27 @@ impl AssetLoaders {
|
||||
.or_default();
|
||||
|
||||
if !list.is_empty() {
|
||||
duplicate_extensions.push(extension);
|
||||
if let Some(existing_loaders_for_type_id) = existing_loaders_for_type_id {
|
||||
if list
|
||||
.iter()
|
||||
.any(|index| existing_loaders_for_type_id.contains(index))
|
||||
{
|
||||
duplicate_extensions.push(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.push(loader_index);
|
||||
}
|
||||
|
||||
let list = self
|
||||
.type_id_to_loaders
|
||||
.entry(loader_asset_type)
|
||||
.or_default();
|
||||
|
||||
let duplicate_asset_registration = !list.is_empty();
|
||||
if !duplicate_extensions.is_empty() && duplicate_asset_registration {
|
||||
if !duplicate_extensions.is_empty() {
|
||||
warn!("Duplicate AssetLoader preregistered for Asset type `{loader_asset_type_name}` with extensions `{duplicate_extensions:?}`. \
|
||||
Loader must be specified in a .meta file in order to load assets of this type with these extensions.");
|
||||
}
|
||||
|
||||
list.push(loader_index);
|
||||
self.type_id_to_loaders
|
||||
.entry(loader_asset_type)
|
||||
.or_default()
|
||||
.push(loader_index);
|
||||
|
||||
let (mut sender, receiver) = async_broadcast::broadcast(1);
|
||||
sender.set_overflow(true);
|
||||
@ -328,6 +341,7 @@ impl<T: AssetLoader> AssetLoader for InstrumentedAssetLoader<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::{format, string::String};
|
||||
use core::marker::PhantomData;
|
||||
use std::{
|
||||
path::Path,
|
||||
@ -341,18 +355,14 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
// The compiler notices these fields are never read and raises a dead_code lint which kill CI.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath, Debug)]
|
||||
struct A(usize);
|
||||
struct A;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath, Debug)]
|
||||
struct B(usize);
|
||||
struct B;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Asset, TypePath, Debug)]
|
||||
struct C(usize);
|
||||
struct C;
|
||||
|
||||
struct Loader<A: Asset, const N: usize, const E: usize> {
|
||||
sender: Sender<()>,
|
||||
|
||||
@ -17,14 +17,16 @@ use crate::{
|
||||
DeserializeMetaError, ErasedLoadedAsset, Handle, LoadedUntypedAsset, UntypedAssetId,
|
||||
UntypedAssetLoadFailedEvent, UntypedHandle,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{borrow::ToOwned, boxed::Box, vec, vec::Vec};
|
||||
use alloc::{
|
||||
format,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
};
|
||||
use atomicow::CowArc;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_tasks::IoTaskPool;
|
||||
use bevy_utils::{
|
||||
tracing::{error, info},
|
||||
HashSet,
|
||||
};
|
||||
use bevy_utils::HashSet;
|
||||
use core::{any::TypeId, future::Future, panic::AssertUnwindSafe, task::Poll};
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use either::Either;
|
||||
@ -34,6 +36,7 @@ use loaders::*;
|
||||
use parking_lot::{RwLock, RwLockWriteGuard};
|
||||
use std::path::{Path, PathBuf};
|
||||
use thiserror::Error;
|
||||
use tracing::{error, info};
|
||||
|
||||
/// Loads and tracks the state of [`Asset`] values from a configured [`AssetReader`](crate::io::AssetReader). This can be used to kick off new asset loads and
|
||||
/// retrieve their current load states.
|
||||
@ -200,7 +203,7 @@ impl AssetServer {
|
||||
loader.ok_or_else(error)?.get().await.map_err(|_| error())
|
||||
}
|
||||
|
||||
/// Returns the registered [`AssetLoader`] associated with the given [`std::any::type_name`], if it exists.
|
||||
/// Returns the registered [`AssetLoader`] associated with the given [`core::any::type_name`], if it exists.
|
||||
pub async fn get_asset_loader_with_type_name(
|
||||
&self,
|
||||
type_name: &str,
|
||||
@ -1474,7 +1477,8 @@ impl AssetServer {
|
||||
pub fn handle_internal_asset_events(world: &mut World) {
|
||||
world.resource_scope(|world, server: Mut<AssetServer>| {
|
||||
let mut infos = server.data.infos.write();
|
||||
let mut untyped_failures = vec![];
|
||||
let var_name = vec![];
|
||||
let mut untyped_failures = var_name;
|
||||
for event in server.data.asset_event_receiver.try_iter() {
|
||||
match event {
|
||||
InternalAssetEvent::Loaded { id, loaded_asset } => {
|
||||
@ -1814,7 +1818,7 @@ pub struct MissingAssetLoaderForExtensionError {
|
||||
extensions: Vec<String>,
|
||||
}
|
||||
|
||||
/// An error that occurs when an [`AssetLoader`] is not registered for a given [`std::any::type_name`].
|
||||
/// An error that occurs when an [`AssetLoader`] is not registered for a given [`core::any::type_name`].
|
||||
#[derive(Error, Debug, Clone, PartialEq, Eq)]
|
||||
#[error("no `AssetLoader` found with the name '{type_name}'")]
|
||||
pub struct MissingAssetLoaderForTypeNameError {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::{meta::Settings, Asset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle};
|
||||
use alloc::boxed::Box;
|
||||
use atomicow::CowArc;
|
||||
use bevy_tasks::ConditionalSendFuture;
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_audio"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides audio functionality for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -10,20 +10,19 @@ keywords = ["bevy"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
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", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
|
||||
|
||||
# other
|
||||
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 }
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![expect(deprecated)]
|
||||
|
||||
use crate::{AudioSource, Decodable, Volume};
|
||||
use bevy_asset::{Asset, Handle};
|
||||
use bevy_ecs::prelude::*;
|
||||
@ -207,13 +205,6 @@ impl Default for SpatialScale {
|
||||
#[reflect(Resource, Default)]
|
||||
pub struct DefaultSpatialScale(pub SpatialScale);
|
||||
|
||||
/// Bundle for playing a standard bevy audio asset
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `AudioPlayer` component instead. Inserting it will now also insert a `PlaybackSettings` component automatically."
|
||||
)]
|
||||
pub type AudioBundle = AudioSourceBundle<AudioSource>;
|
||||
|
||||
/// A component for playing a sound.
|
||||
///
|
||||
/// Insert this component onto an entity to trigger an audio source to begin playing.
|
||||
@ -252,48 +243,3 @@ impl AudioPlayer<AudioSource> {
|
||||
Self(source)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bundle for playing a sound.
|
||||
///
|
||||
/// Insert this bundle onto an entity to trigger a sound source to begin playing.
|
||||
///
|
||||
/// If the handle refers to an unavailable asset (such as if it has not finished loading yet),
|
||||
/// the audio will not begin playing immediately. The audio will play when the asset is ready.
|
||||
///
|
||||
/// When Bevy begins the audio playback, an [`AudioSink`][crate::AudioSink] component will be
|
||||
/// added to the entity. You can use that component to control the audio settings during playback.
|
||||
#[derive(Bundle)]
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `AudioPlayer` component instead. Inserting it will now also insert a `PlaybackSettings` component automatically."
|
||||
)]
|
||||
pub struct AudioSourceBundle<Source = AudioSource>
|
||||
where
|
||||
Source: Asset + Decodable,
|
||||
{
|
||||
/// Asset containing the audio data to play.
|
||||
pub source: AudioPlayer<Source>,
|
||||
/// Initial settings that the audio starts playing with.
|
||||
/// If you would like to control the audio while it is playing,
|
||||
/// query for the [`AudioSink`][crate::AudioSink] component.
|
||||
/// Changes to this component will *not* be applied to already-playing audio.
|
||||
pub settings: PlaybackSettings,
|
||||
}
|
||||
|
||||
impl<T: Asset + Decodable> Clone for AudioSourceBundle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
source: self.source.clone(),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Decodable + Asset> Default for AudioSourceBundle<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
source: AudioPlayer(Handle::default()),
|
||||
settings: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,10 @@ use crate::{
|
||||
};
|
||||
use bevy_asset::{Asset, Assets};
|
||||
use bevy_ecs::{prelude::*, system::SystemParam};
|
||||
use bevy_hierarchy::DespawnRecursiveExt;
|
||||
use bevy_math::Vec3;
|
||||
use bevy_transform::prelude::GlobalTransform;
|
||||
use bevy_utils::tracing::warn;
|
||||
use rodio::{OutputStream, OutputStreamHandle, Sink, Source, SpatialSink};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{AudioSink, AudioSinkPlayback};
|
||||
|
||||
@ -47,11 +46,11 @@ impl Default for AudioOutput {
|
||||
}
|
||||
|
||||
/// Marker for internal use, to despawn entities when playback finishes.
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Default)]
|
||||
pub struct PlaybackDespawnMarker;
|
||||
|
||||
/// Marker for internal use, to remove audio components when playback finishes.
|
||||
#[derive(Component)]
|
||||
#[derive(Component, Default)]
|
||||
pub struct PlaybackRemoveMarker;
|
||||
|
||||
#[derive(SystemParam)]
|
||||
@ -253,12 +252,12 @@ pub(crate) fn cleanup_finished_audio<T: Decodable + Asset>(
|
||||
) {
|
||||
for (entity, sink) in &query_nonspatial_despawn {
|
||||
if sink.sink.empty() {
|
||||
commands.entity(entity).despawn_recursive();
|
||||
commands.entity(entity).despawn();
|
||||
}
|
||||
}
|
||||
for (entity, sink) in &query_spatial_despawn {
|
||||
if sink.sink.empty() {
|
||||
commands.entity(entity).despawn_recursive();
|
||||
commands.entity(entity).despawn();
|
||||
}
|
||||
}
|
||||
for (entity, sink) in &query_nonspatial_remove {
|
||||
|
||||
@ -39,13 +39,11 @@ mod volume;
|
||||
/// The audio prelude.
|
||||
///
|
||||
/// This includes the most common types in this crate, re-exported for your convenience.
|
||||
#[expect(deprecated)]
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
AudioBundle, AudioPlayer, AudioSink, AudioSinkPlayback, AudioSource, AudioSourceBundle,
|
||||
Decodable, GlobalVolume, Pitch, PitchBundle, PlaybackSettings, SpatialAudioSink,
|
||||
SpatialListener,
|
||||
AudioPlayer, AudioSink, AudioSinkPlayback, AudioSource, Decodable, GlobalVolume, Pitch,
|
||||
PlaybackSettings, SpatialAudioSink, SpatialListener,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#![expect(deprecated)]
|
||||
|
||||
use crate::{AudioSourceBundle, Decodable};
|
||||
use crate::Decodable;
|
||||
use bevy_asset::Asset;
|
||||
use bevy_reflect::TypePath;
|
||||
use rodio::{
|
||||
@ -35,10 +33,3 @@ impl Decodable for Pitch {
|
||||
SineWave::new(self.frequency).take_duration(self.duration)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bundle for playing a bevy note sound
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `AudioPlayer<Pitch>` component instead. Inserting it will now also insert a `PlaybackSettings` component automatically."
|
||||
)]
|
||||
pub type PitchBundle = AudioSourceBundle<Pitch>;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_color"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
description = "Types for representing and manipulating color values"
|
||||
homepage = "https://bevyengine.org"
|
||||
@ -10,10 +10,10 @@ keywords = ["bevy", "color"]
|
||||
rust-version = "1.83.0"
|
||||
|
||||
[dependencies]
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = false, features = [
|
||||
bevy_math = { path = "../bevy_math", version = "0.16.0-dev", default-features = false, features = [
|
||||
"curve",
|
||||
] }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"bevy",
|
||||
], optional = true }
|
||||
bytemuck = { version = "1", features = ["derive"] }
|
||||
|
||||
@ -84,12 +84,6 @@ impl Color {
|
||||
(*self).into()
|
||||
}
|
||||
|
||||
#[deprecated = "Use `Color::srgba` instead"]
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color.
|
||||
pub const fn rgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||
Self::srgba(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color.
|
||||
pub const fn srgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||
Self::Srgba(Srgba {
|
||||
@ -100,12 +94,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use `Color::srgb` instead"]
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
|
||||
pub const fn rgb(red: f32, green: f32, blue: f32) -> Self {
|
||||
Self::srgb(red, green, blue)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
|
||||
pub const fn srgb(red: f32, green: f32, blue: f32) -> Self {
|
||||
Self::Srgba(Srgba {
|
||||
@ -116,12 +104,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use `Color::srgb_from_array` instead"]
|
||||
/// Reads an array of floats to creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
|
||||
pub fn rgb_from_array([r, g, b]: [f32; 3]) -> Self {
|
||||
Self::Srgba(Srgba::rgb(r, g, b))
|
||||
}
|
||||
|
||||
/// Reads an array of floats to creates a new [`Color`] object storing a [`Srgba`] color with an alpha of 1.0.
|
||||
pub const fn srgb_from_array(array: [f32; 3]) -> Self {
|
||||
Self::Srgba(Srgba {
|
||||
@ -132,14 +114,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use `Color::srgba_u8` instead"]
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values.
|
||||
///
|
||||
/// A value of 0 is interpreted as 0.0, and a value of 255 is interpreted as 1.0.
|
||||
pub fn rgba_u8(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
|
||||
Self::srgba_u8(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values.
|
||||
///
|
||||
/// A value of 0 is interpreted as 0.0, and a value of 255 is interpreted as 1.0.
|
||||
@ -152,14 +126,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use `Color::srgb_u8` instead"]
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values with an alpha of 1.0.
|
||||
///
|
||||
/// A value of 0 is interpreted as 0.0, and a value of 255 is interpreted as 1.0.
|
||||
pub fn rgb_u8(red: u8, green: u8, blue: u8) -> Self {
|
||||
Self::srgb_u8(red, green, blue)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`Srgba`] color from [`u8`] values with an alpha of 1.0.
|
||||
///
|
||||
/// A value of 0 is interpreted as 0.0, and a value of 255 is interpreted as 1.0.
|
||||
@ -172,12 +138,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use Color::linear_rgba instead."]
|
||||
/// Creates a new [`Color`] object storing a [`LinearRgba`] color.
|
||||
pub const fn rbga_linear(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||
Self::linear_rgba(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`LinearRgba`] color.
|
||||
pub const fn linear_rgba(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||
Self::LinearRgba(LinearRgba {
|
||||
@ -188,12 +148,6 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated = "Use Color::linear_rgb instead."]
|
||||
/// Creates a new [`Color`] object storing a [`LinearRgba`] color with an alpha of 1.0.
|
||||
pub const fn rgb_linear(red: f32, green: f32, blue: f32) -> Self {
|
||||
Self::linear_rgb(red, green, blue)
|
||||
}
|
||||
|
||||
/// Creates a new [`Color`] object storing a [`LinearRgba`] color with an alpha of 1.0.
|
||||
pub const fn linear_rgb(red: f32, green: f32, blue: f32) -> Self {
|
||||
Self::LinearRgba(LinearRgba {
|
||||
|
||||
@ -145,7 +145,14 @@ pub use srgba::*;
|
||||
pub use xyza::*;
|
||||
|
||||
/// Describes the traits that a color should implement for consistency.
|
||||
#[allow(dead_code)] // This is an internal marker trait used to ensure that our color types impl the required traits
|
||||
#[expect(
|
||||
clippy::allow_attributes,
|
||||
reason = "If the below attribute on `dead_code` is removed, then rustc complains that `StandardColor` is dead code. However, if we `expect` the `dead_code` lint, then rustc complains of an unfulfilled expectation."
|
||||
)]
|
||||
#[allow(
|
||||
dead_code,
|
||||
reason = "This is an internal marker trait used to ensure that our color types impl the required traits"
|
||||
)]
|
||||
pub(crate) trait StandardColor
|
||||
where
|
||||
Self: core::fmt::Debug,
|
||||
|
||||
@ -224,8 +224,8 @@ impl From<LinearRgba> for Oklaba {
|
||||
blue,
|
||||
alpha,
|
||||
} = value;
|
||||
// From https://github.com/DougLau/pix
|
||||
// Floats literals are truncated from the source code above, to avoid excessive precision.
|
||||
// From https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab
|
||||
// Float literals are truncated to avoid excessive precision.
|
||||
let l = 0.41222146 * red + 0.53633255 * green + 0.051445995 * blue;
|
||||
let m = 0.2119035 * red + 0.6806995 * green + 0.10739696 * blue;
|
||||
let s = 0.08830246 * red + 0.28171885 * green + 0.6299787 * blue;
|
||||
@ -248,8 +248,8 @@ impl From<Oklaba> for LinearRgba {
|
||||
alpha,
|
||||
} = value;
|
||||
|
||||
// From https://github.com/Ogeon/palette/blob/e75eab2fb21af579353f51f6229a510d0d50a311/palette/src/oklab.rs#L312-L332
|
||||
// Floats literals are truncated from the source code above, to avoid excessive precision.
|
||||
// From https://bottosson.github.io/posts/oklab/#converting-from-linear-srgb-to-oklab
|
||||
// Float literals are truncated to avoid excessive precision.
|
||||
let l_ = lightness + 0.39633778 * a + 0.21580376 * b;
|
||||
let m_ = lightness - 0.105561346 * a - 0.06385417 * b;
|
||||
let s_ = lightness - 0.08948418 * a - 1.2914855 * b;
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
use crate::Srgba;
|
||||
|
||||
// The CSS4 colors are a superset of the CSS1 colors, so we can just re-export the CSS1 colors.
|
||||
#[allow(unused_imports)]
|
||||
pub use crate::palettes::basic::*;
|
||||
|
||||
/// <div style="background-color:rgb(94.1%, 97.3%, 100.0%); width: 10px; padding: 10px; border: 1px solid;"></div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bevy_core_pipeline"
|
||||
version = "0.15.0-dev"
|
||||
version = "0.16.0-dev"
|
||||
edition = "2021"
|
||||
authors = [
|
||||
"Bevy Contributors <bevyengine@gmail.com>",
|
||||
@ -22,19 +22,19 @@ smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
|
||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.15.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" }
|
||||
bevy_render = { path = "../bevy_render", version = "0.15.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_window = { path = "../bevy_window", version = "0.15.0-dev" }
|
||||
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" }
|
||||
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
bitflags = "2.3"
|
||||
@ -42,6 +42,7 @@ radsort = "0.1"
|
||||
nonmax = "0.5"
|
||||
smallvec = "1"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -136,7 +136,10 @@ impl AutoExposureCompensationCurve {
|
||||
let lut_inv_range = 1.0 / (lut_end - lut_begin);
|
||||
|
||||
// Iterate over all LUT entries whose pixel centers fall within the current segment.
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
#[expect(
|
||||
clippy::needless_range_loop,
|
||||
reason = "This for-loop also uses `i` to calculate a value `t`."
|
||||
)]
|
||||
for i in lut_begin.ceil() as usize..=lut_end.floor() as usize {
|
||||
let t = (i as f32 - lut_begin) * lut_inv_range;
|
||||
lut[i] = previous.y.lerp(current.y, t);
|
||||
|
||||
@ -24,8 +24,7 @@ use node::AutoExposureNode;
|
||||
use pipeline::{
|
||||
AutoExposurePass, AutoExposurePipeline, ViewAutoExposurePipeline, METERING_SHADER_HANDLE,
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
pub use settings::{AutoExposure, AutoExposureSettings};
|
||||
pub use settings::AutoExposure;
|
||||
|
||||
use crate::{
|
||||
auto_exposure::compensation_curve::GpuAutoExposureCompensationCurve,
|
||||
|
||||
@ -88,9 +88,6 @@ pub struct AutoExposure {
|
||||
pub compensation_curve: Handle<AutoExposureCompensationCurve>,
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.15.0", note = "Renamed to `AutoExposure`")]
|
||||
pub type AutoExposureSettings = AutoExposure;
|
||||
|
||||
impl Default for AutoExposure {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
struct BloomUniforms {
|
||||
threshold_precomputations: vec4<f32>,
|
||||
viewport: vec4<f32>,
|
||||
scale: vec2<f32>,
|
||||
aspect: f32,
|
||||
uv_offset: f32
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var input_texture: texture_2d<f32>;
|
||||
@ -51,6 +51,14 @@ fn karis_average(color: vec3<f32>) -> f32 {
|
||||
|
||||
// [COD] slide 153
|
||||
fn sample_input_13_tap(uv: vec2<f32>) -> vec3<f32> {
|
||||
#ifdef UNIFORM_SCALE
|
||||
// This is the fast path. When the bloom scale is uniform, the 13 tap sampling kernel can be
|
||||
// expressed with constant offsets.
|
||||
//
|
||||
// It's possible that this isn't meaningfully faster than the "slow" path. However, because it
|
||||
// is hard to test performance on all platforms, and uniform bloom is the most common case, this
|
||||
// path was retained when adding non-uniform (anamorphic) bloom. This adds a small, but nonzero,
|
||||
// cost to maintainability, but it does help me sleep at night.
|
||||
let a = textureSample(input_texture, s, uv, vec2<i32>(-2, 2)).rgb;
|
||||
let b = textureSample(input_texture, s, uv, vec2<i32>(0, 2)).rgb;
|
||||
let c = textureSample(input_texture, s, uv, vec2<i32>(2, 2)).rgb;
|
||||
@ -64,6 +72,35 @@ fn sample_input_13_tap(uv: vec2<f32>) -> vec3<f32> {
|
||||
let k = textureSample(input_texture, s, uv, vec2<i32>(1, 1)).rgb;
|
||||
let l = textureSample(input_texture, s, uv, vec2<i32>(-1, -1)).rgb;
|
||||
let m = textureSample(input_texture, s, uv, vec2<i32>(1, -1)).rgb;
|
||||
#else
|
||||
// This is the flexible, but potentially slower, path for non-uniform sampling. Because the
|
||||
// sample is not a constant, and it can fall outside of the limits imposed on constant sample
|
||||
// offsets (-8..8), we have to compute the pixel offset in uv coordinates using the size of the
|
||||
// texture.
|
||||
//
|
||||
// It isn't clear if this is meaningfully slower than using the offset syntax, the spec doesn't
|
||||
// mention it anywhere: https://www.w3.org/TR/WGSL/#texturesample, but the fact that the offset
|
||||
// syntax uses a const-expr implies that it allows some compiler optimizations - maybe more
|
||||
// impactful on mobile?
|
||||
let scale = uniforms.scale;
|
||||
let ps = scale / vec2<f32>(textureDimensions(input_texture));
|
||||
let pl = 2.0 * ps;
|
||||
let ns = -1.0 * ps;
|
||||
let nl = -2.0 * ps;
|
||||
let a = textureSample(input_texture, s, uv + vec2<f32>(nl.x, pl.y)).rgb;
|
||||
let b = textureSample(input_texture, s, uv + vec2<f32>(0.00, pl.y)).rgb;
|
||||
let c = textureSample(input_texture, s, uv + vec2<f32>(pl.x, pl.y)).rgb;
|
||||
let d = textureSample(input_texture, s, uv + vec2<f32>(nl.x, 0.00)).rgb;
|
||||
let e = textureSample(input_texture, s, uv).rgb;
|
||||
let f = textureSample(input_texture, s, uv + vec2<f32>(pl.x, 0.00)).rgb;
|
||||
let g = textureSample(input_texture, s, uv + vec2<f32>(nl.x, nl.y)).rgb;
|
||||
let h = textureSample(input_texture, s, uv + vec2<f32>(0.00, nl.y)).rgb;
|
||||
let i = textureSample(input_texture, s, uv + vec2<f32>(pl.x, nl.y)).rgb;
|
||||
let j = textureSample(input_texture, s, uv + vec2<f32>(ns.x, ps.y)).rgb;
|
||||
let k = textureSample(input_texture, s, uv + vec2<f32>(ps.x, ps.y)).rgb;
|
||||
let l = textureSample(input_texture, s, uv + vec2<f32>(ns.x, ns.y)).rgb;
|
||||
let m = textureSample(input_texture, s, uv + vec2<f32>(ps.x, ns.y)).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef FIRST_DOWNSAMPLE
|
||||
// [COD] slide 168
|
||||
@ -95,9 +132,11 @@ fn sample_input_13_tap(uv: vec2<f32>) -> vec3<f32> {
|
||||
|
||||
// [COD] slide 162
|
||||
fn sample_input_3x3_tent(uv: vec2<f32>) -> vec3<f32> {
|
||||
// UV offsets configured from uniforms.
|
||||
let x = uniforms.uv_offset / uniforms.aspect;
|
||||
let y = uniforms.uv_offset;
|
||||
// While this is probably technically incorrect, it makes nonuniform bloom smoother, without
|
||||
// having any impact on uniform bloom, which simply evaluates to 1.0 here.
|
||||
let frag_size = uniforms.scale / vec2<f32>(textureDimensions(input_texture));
|
||||
let x = frag_size.x;
|
||||
let y = frag_size.y;
|
||||
|
||||
let a = textureSample(input_texture, s, vec2<f32>(uv.x - x, uv.y + y)).rgb;
|
||||
let b = textureSample(input_texture, s, vec2<f32>(uv.x, uv.y + y)).rgb;
|
||||
|
||||
@ -5,7 +5,7 @@ use bevy_ecs::{
|
||||
system::{Commands, Query, Res, ResMut, Resource},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use bevy_math::Vec4;
|
||||
use bevy_math::{Vec2, Vec4};
|
||||
use bevy_render::{
|
||||
render_resource::{
|
||||
binding_types::{sampler, texture_2d, uniform_buffer},
|
||||
@ -31,6 +31,7 @@ pub struct BloomDownsamplingPipeline {
|
||||
pub struct BloomDownsamplingPipelineKeys {
|
||||
prefilter: bool,
|
||||
first_downsample: bool,
|
||||
uniform_scale: bool,
|
||||
}
|
||||
|
||||
/// The uniform struct extracted from [`Bloom`] attached to a Camera.
|
||||
@ -40,8 +41,8 @@ pub struct BloomUniforms {
|
||||
// Precomputed values used when thresholding, see https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/#3.4
|
||||
pub threshold_precomputations: Vec4,
|
||||
pub viewport: Vec4,
|
||||
pub scale: Vec2,
|
||||
pub aspect: f32,
|
||||
pub uv_offset: f32,
|
||||
}
|
||||
|
||||
impl FromWorld for BloomDownsamplingPipeline {
|
||||
@ -102,6 +103,10 @@ impl SpecializedRenderPipeline for BloomDownsamplingPipeline {
|
||||
shader_defs.push("USE_THRESHOLD".into());
|
||||
}
|
||||
|
||||
if key.uniform_scale {
|
||||
shader_defs.push("UNIFORM_SCALE".into());
|
||||
}
|
||||
|
||||
RenderPipelineDescriptor {
|
||||
label: Some(
|
||||
if key.first_downsample {
|
||||
@ -148,6 +153,7 @@ pub fn prepare_downsampling_pipeline(
|
||||
BloomDownsamplingPipelineKeys {
|
||||
prefilter,
|
||||
first_downsample: false,
|
||||
uniform_scale: bloom.scale == Vec2::ONE,
|
||||
},
|
||||
);
|
||||
|
||||
@ -157,6 +163,7 @@ pub fn prepare_downsampling_pipeline(
|
||||
BloomDownsamplingPipelineKeys {
|
||||
prefilter,
|
||||
first_downsample: true,
|
||||
uniform_scale: bloom.scale == Vec2::ONE,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -3,10 +3,7 @@ mod settings;
|
||||
mod upsampling_pipeline;
|
||||
|
||||
use bevy_color::{Gray, LinearRgba};
|
||||
#[allow(deprecated)]
|
||||
pub use settings::{
|
||||
Bloom, BloomCompositeMode, BloomPrefilter, BloomPrefilterSettings, BloomSettings,
|
||||
};
|
||||
pub use settings::{Bloom, BloomCompositeMode, BloomPrefilter};
|
||||
|
||||
use crate::{
|
||||
core_2d::graph::{Core2d, Node2d},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use super::downsampling_pipeline::BloomUniforms;
|
||||
use bevy_ecs::{prelude::Component, query::QueryItem, reflect::ReflectComponent};
|
||||
use bevy_math::{AspectRatio, URect, UVec4, Vec4};
|
||||
use bevy_math::{AspectRatio, URect, UVec4, Vec2, Vec4};
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_render::{extract_component::ExtractComponent, prelude::Camera};
|
||||
|
||||
@ -113,17 +113,14 @@ pub struct Bloom {
|
||||
/// Only tweak if you are seeing visual artifacts.
|
||||
pub max_mip_dimension: u32,
|
||||
|
||||
/// UV offset for bloom shader. Ideally close to 2.0 / `max_mip_dimension`.
|
||||
/// Only tweak if you are seeing visual artifacts.
|
||||
pub uv_offset: f32,
|
||||
/// Amount to stretch the bloom on each axis. Artistic control, can be used to emulate
|
||||
/// anamorphic blur by using a large x-value. For large values, you may need to increase
|
||||
/// [`Bloom::max_mip_dimension`] to reduce sampling artifacts.
|
||||
pub scale: Vec2,
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.15.0", note = "Renamed to `Bloom`")]
|
||||
pub type BloomSettings = Bloom;
|
||||
|
||||
impl Bloom {
|
||||
const DEFAULT_MAX_MIP_DIMENSION: u32 = 512;
|
||||
const DEFAULT_UV_OFFSET: f32 = 0.004;
|
||||
|
||||
/// The default bloom preset.
|
||||
///
|
||||
@ -139,7 +136,15 @@ impl Bloom {
|
||||
},
|
||||
composite_mode: BloomCompositeMode::EnergyConserving,
|
||||
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
|
||||
uv_offset: Self::DEFAULT_UV_OFFSET,
|
||||
scale: Vec2::ONE,
|
||||
};
|
||||
|
||||
/// Emulates the look of stylized anamorphic bloom, stretched horizontally.
|
||||
pub const ANAMORPHIC: Self = Self {
|
||||
// The larger scale necessitates a larger resolution to reduce artifacts:
|
||||
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION * 2,
|
||||
scale: Vec2::new(4.0, 1.0),
|
||||
..Self::NATURAL
|
||||
};
|
||||
|
||||
/// A preset that's similar to how older games did bloom.
|
||||
@ -154,7 +159,7 @@ impl Bloom {
|
||||
},
|
||||
composite_mode: BloomCompositeMode::Additive,
|
||||
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
|
||||
uv_offset: Self::DEFAULT_UV_OFFSET,
|
||||
scale: Vec2::ONE,
|
||||
};
|
||||
|
||||
/// A preset that applies a very strong bloom, and blurs the whole screen.
|
||||
@ -169,7 +174,7 @@ impl Bloom {
|
||||
},
|
||||
composite_mode: BloomCompositeMode::EnergyConserving,
|
||||
max_mip_dimension: Self::DEFAULT_MAX_MIP_DIMENSION,
|
||||
uv_offset: Self::DEFAULT_UV_OFFSET,
|
||||
scale: Vec2::ONE,
|
||||
};
|
||||
}
|
||||
|
||||
@ -203,9 +208,6 @@ pub struct BloomPrefilter {
|
||||
pub threshold_softness: f32,
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.15.0", note = "Renamed to `BloomPrefilter`")]
|
||||
pub type BloomPrefilterSettings = BloomPrefilter;
|
||||
|
||||
#[derive(Debug, Clone, Reflect, PartialEq, Eq, Hash, Copy)]
|
||||
pub enum BloomCompositeMode {
|
||||
EnergyConserving,
|
||||
@ -246,7 +248,7 @@ impl ExtractComponent for Bloom {
|
||||
aspect: AspectRatio::try_from_pixels(size.x, size.y)
|
||||
.expect("Valid screen size values for Bloom settings")
|
||||
.ratio(),
|
||||
uv_offset: bloom.uv_offset,
|
||||
scale: bloom.scale,
|
||||
};
|
||||
|
||||
Some((bloom.clone(), uniform))
|
||||
|
||||
@ -54,9 +54,6 @@ pub struct ContrastAdaptiveSharpening {
|
||||
pub denoise: bool,
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.15.0", note = "Renamed to `ContrastAdaptiveSharpening`")]
|
||||
pub type ContrastAdaptiveSharpeningSettings = ContrastAdaptiveSharpening;
|
||||
|
||||
impl Default for ContrastAdaptiveSharpening {
|
||||
fn default() -> Self {
|
||||
ContrastAdaptiveSharpening {
|
||||
|
||||
@ -1,21 +1,13 @@
|
||||
#![expect(deprecated)]
|
||||
|
||||
use crate::{
|
||||
core_2d::graph::Core2d,
|
||||
tonemapping::{DebandDither, Tonemapping},
|
||||
};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||
use bevy_render::sync_world::SyncToRenderWorld;
|
||||
use bevy_render::{
|
||||
camera::{
|
||||
Camera, CameraMainTextureUsages, CameraProjection, CameraRenderGraph,
|
||||
OrthographicProjection, Projection,
|
||||
},
|
||||
camera::{Camera, CameraProjection, CameraRenderGraph, OrthographicProjection, Projection},
|
||||
extract_component::ExtractComponent,
|
||||
prelude::Msaa,
|
||||
primitives::Frustum,
|
||||
view::VisibleEntities,
|
||||
};
|
||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||
|
||||
@ -32,82 +24,3 @@ use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||
Tonemapping(|| Tonemapping::None),
|
||||
)]
|
||||
pub struct Camera2d;
|
||||
|
||||
#[derive(Bundle, Clone)]
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `Camera2d` component instead. Inserting it will now also insert the other components required by it automatically."
|
||||
)]
|
||||
pub struct Camera2dBundle {
|
||||
pub camera: Camera,
|
||||
pub camera_render_graph: CameraRenderGraph,
|
||||
pub projection: Projection,
|
||||
pub visible_entities: VisibleEntities,
|
||||
pub frustum: Frustum,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
pub camera_2d: Camera2d,
|
||||
pub tonemapping: Tonemapping,
|
||||
pub deband_dither: DebandDither,
|
||||
pub main_texture_usages: CameraMainTextureUsages,
|
||||
pub msaa: Msaa,
|
||||
/// Marker component that indicates that its entity needs to be synchronized to the render world
|
||||
pub sync: SyncToRenderWorld,
|
||||
}
|
||||
|
||||
impl Default for Camera2dBundle {
|
||||
fn default() -> Self {
|
||||
let projection = Projection::Orthographic(OrthographicProjection::default_2d());
|
||||
let transform = Transform::default();
|
||||
let frustum = projection.compute_frustum(&GlobalTransform::from(transform));
|
||||
Self {
|
||||
camera_render_graph: CameraRenderGraph::new(Core2d),
|
||||
projection,
|
||||
visible_entities: VisibleEntities::default(),
|
||||
frustum,
|
||||
transform,
|
||||
global_transform: Default::default(),
|
||||
camera: Camera::default(),
|
||||
camera_2d: Camera2d,
|
||||
tonemapping: Tonemapping::None,
|
||||
deband_dither: DebandDither::Disabled,
|
||||
main_texture_usages: Default::default(),
|
||||
msaa: Default::default(),
|
||||
sync: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Camera2dBundle {
|
||||
/// Create an orthographic projection camera with a custom `Z` position.
|
||||
///
|
||||
/// The camera is placed at `Z=far-0.1`, looking toward the world origin `(0,0,0)`.
|
||||
/// Its orthographic projection extends from `0.0` to `-far` in camera view space,
|
||||
/// corresponding to `Z=far-0.1` (closest to camera) to `Z=-0.1` (furthest away from
|
||||
/// camera) in world space.
|
||||
pub fn new_with_far(far: f32) -> Self {
|
||||
// we want 0 to be "closest" and +far to be "farthest" in 2d, so we offset
|
||||
// the camera's translation by far and use a right handed coordinate system
|
||||
let projection = Projection::Orthographic(OrthographicProjection {
|
||||
far,
|
||||
..OrthographicProjection::default_2d()
|
||||
});
|
||||
let transform = Transform::from_xyz(0.0, 0.0, far - 0.1);
|
||||
let frustum = projection.compute_frustum(&GlobalTransform::from(transform));
|
||||
Self {
|
||||
camera_render_graph: CameraRenderGraph::new(Core2d),
|
||||
projection,
|
||||
visible_entities: VisibleEntities::default(),
|
||||
frustum,
|
||||
transform,
|
||||
global_transform: Default::default(),
|
||||
camera: Camera::default(),
|
||||
camera_2d: Camera2d,
|
||||
tonemapping: Tonemapping::None,
|
||||
deband_dither: DebandDither::Disabled,
|
||||
main_texture_usages: Default::default(),
|
||||
msaa: Default::default(),
|
||||
sync: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,11 +7,11 @@ use bevy_render::{
|
||||
render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
|
||||
render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::{ViewDepthTexture, ViewTarget},
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use tracing::info_span;
|
||||
|
||||
use super::AlphaMask2d;
|
||||
|
||||
@ -22,6 +22,7 @@ pub struct MainOpaquePass2dNode;
|
||||
impl ViewNode for MainOpaquePass2dNode {
|
||||
type ViewQuery = (
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static ViewTarget,
|
||||
&'static ViewDepthTexture,
|
||||
);
|
||||
@ -30,7 +31,7 @@ impl ViewNode for MainOpaquePass2dNode {
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(camera, 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)) = (
|
||||
@ -47,8 +48,8 @@ impl ViewNode for MainOpaquePass2dNode {
|
||||
|
||||
let view_entity = graph.view_entity();
|
||||
let (Some(opaque_phase), Some(alpha_mask_phase)) = (
|
||||
opaque_phases.get(&view_entity),
|
||||
alpha_mask_phases.get(&view_entity),
|
||||
opaque_phases.get(&view.retained_view_entity),
|
||||
alpha_mask_phases.get(&view.retained_view_entity),
|
||||
) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
@ -7,11 +7,11 @@ use bevy_render::{
|
||||
render_phase::ViewSortedRenderPhases,
|
||||
render_resource::{RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::{ViewDepthTexture, ViewTarget},
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use tracing::info_span;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MainTransparentPass2dNode {}
|
||||
@ -19,6 +19,7 @@ pub struct MainTransparentPass2dNode {}
|
||||
impl ViewNode for MainTransparentPass2dNode {
|
||||
type ViewQuery = (
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static ViewTarget,
|
||||
&'static ViewDepthTexture,
|
||||
);
|
||||
@ -27,7 +28,7 @@ impl ViewNode for MainTransparentPass2dNode {
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(camera, 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) =
|
||||
@ -37,7 +38,7 @@ impl ViewNode for MainTransparentPass2dNode {
|
||||
};
|
||||
|
||||
let view_entity = graph.view_entity();
|
||||
let Some(transparent_phase) = transparent_phases.get(&view_entity) else {
|
||||
let Some(transparent_phase) = transparent_phases.get(&view.retained_view_entity) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
||||
@ -34,16 +34,18 @@ use core::ops::Range;
|
||||
|
||||
use bevy_asset::UntypedAssetId;
|
||||
use bevy_render::{
|
||||
batching::gpu_preprocessing::GpuPreprocessingMode, render_phase::PhaseItemBinKey,
|
||||
batching::gpu_preprocessing::GpuPreprocessingMode,
|
||||
render_phase::PhaseItemBatchSetKey,
|
||||
view::{ExtractedView, RetainedViewEntity},
|
||||
};
|
||||
use bevy_utils::HashMap;
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
pub use camera_2d::*;
|
||||
pub use main_opaque_pass_2d_node::*;
|
||||
pub use main_transparent_pass_2d_node::*;
|
||||
|
||||
use crate::{tonemapping::TonemappingNode, upscaling::UpscalingNode};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{entity::EntityHashSet, prelude::*};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::FloatOrd;
|
||||
use bevy_render::{
|
||||
camera::{Camera, ExtractedCamera},
|
||||
@ -59,7 +61,7 @@ use bevy_render::{
|
||||
TextureFormat, TextureUsages,
|
||||
},
|
||||
renderer::RenderDevice,
|
||||
sync_world::{MainEntity, RenderEntity},
|
||||
sync_world::MainEntity,
|
||||
texture::TextureCache,
|
||||
view::{Msaa, ViewDepthTexture},
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
@ -127,8 +129,13 @@ impl Plugin for Core2dPlugin {
|
||||
|
||||
/// Opaque 2D [`BinnedPhaseItem`]s.
|
||||
pub struct Opaque2d {
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: BatchSetKey2d,
|
||||
/// The key, which determines which can be batched.
|
||||
pub key: Opaque2dBinKey,
|
||||
pub bin_key: Opaque2dBinKey,
|
||||
/// An entity from which data will be fetched, including the mesh if
|
||||
/// applicable.
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
@ -155,14 +162,6 @@ pub struct Opaque2dBinKey {
|
||||
pub material_bind_group_id: Option<BindGroupId>,
|
||||
}
|
||||
|
||||
impl PhaseItemBinKey for Opaque2dBinKey {
|
||||
type BatchSetKey = ();
|
||||
|
||||
fn get_batch_set_key(&self) -> Option<Self::BatchSetKey> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PhaseItem for Opaque2d {
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
@ -175,7 +174,7 @@ impl PhaseItem for Opaque2d {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.draw_function
|
||||
self.bin_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -198,16 +197,22 @@ impl PhaseItem for Opaque2d {
|
||||
}
|
||||
|
||||
impl BinnedPhaseItem for Opaque2d {
|
||||
// Since 2D meshes presently can't be multidrawn, the batch set key is
|
||||
// irrelevant.
|
||||
type BatchSetKey = BatchSetKey2d;
|
||||
|
||||
type BinKey = Opaque2dBinKey;
|
||||
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
Opaque2d {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -215,17 +220,36 @@ impl BinnedPhaseItem for Opaque2d {
|
||||
}
|
||||
}
|
||||
|
||||
/// 2D meshes aren't currently multi-drawn together, so this batch set key only
|
||||
/// stores whether the mesh is indexed.
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
pub struct BatchSetKey2d {
|
||||
/// True if the mesh is indexed.
|
||||
pub indexed: bool,
|
||||
}
|
||||
|
||||
impl PhaseItemBatchSetKey for BatchSetKey2d {
|
||||
fn indexed(&self) -> bool {
|
||||
self.indexed
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedRenderPipelinePhaseItem for Opaque2d {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.pipeline
|
||||
self.bin_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
/// Alpha mask 2D [`BinnedPhaseItem`]s.
|
||||
pub struct AlphaMask2d {
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: BatchSetKey2d,
|
||||
/// The key, which determines which can be batched.
|
||||
pub key: AlphaMask2dBinKey,
|
||||
pub bin_key: AlphaMask2dBinKey,
|
||||
/// An entity from which data will be fetched, including the mesh if
|
||||
/// applicable.
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
@ -265,7 +289,7 @@ impl PhaseItem for AlphaMask2d {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.draw_function
|
||||
self.bin_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -288,16 +312,20 @@ impl PhaseItem for AlphaMask2d {
|
||||
}
|
||||
|
||||
impl BinnedPhaseItem for AlphaMask2d {
|
||||
type BatchSetKey = BatchSetKey2d;
|
||||
|
||||
type BinKey = AlphaMask2dBinKey;
|
||||
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
AlphaMask2d {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -305,18 +333,10 @@ impl BinnedPhaseItem for AlphaMask2d {
|
||||
}
|
||||
}
|
||||
|
||||
impl PhaseItemBinKey for AlphaMask2dBinKey {
|
||||
type BatchSetKey = ();
|
||||
|
||||
fn get_batch_set_key(&self) -> Option<Self::BatchSetKey> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedRenderPipelinePhaseItem for AlphaMask2d {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.pipeline
|
||||
self.bin_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,6 +348,9 @@ pub struct Transparent2d {
|
||||
pub draw_function: DrawFunctionId,
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
/// Whether the mesh in question is indexed (uses an index buffer in
|
||||
/// addition to its vertex buffer).
|
||||
pub indexed: bool,
|
||||
}
|
||||
|
||||
impl PhaseItem for Transparent2d {
|
||||
@ -380,6 +403,10 @@ impl SortedPhaseItem for Transparent2d {
|
||||
// radsort is a stable radix sort that performed better than `slice::sort_by_key` or `slice::sort_unstable_by_key`.
|
||||
radsort::sort_by_key(items, |item| item.sort_key().0);
|
||||
}
|
||||
|
||||
fn indexed(&self) -> bool {
|
||||
self.indexed
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedRenderPipelinePhaseItem for Transparent2d {
|
||||
@ -393,20 +420,24 @@ pub fn extract_core_2d_camera_phases(
|
||||
mut transparent_2d_phases: ResMut<ViewSortedRenderPhases<Transparent2d>>,
|
||||
mut opaque_2d_phases: ResMut<ViewBinnedRenderPhases<Opaque2d>>,
|
||||
mut alpha_mask_2d_phases: ResMut<ViewBinnedRenderPhases<AlphaMask2d>>,
|
||||
cameras_2d: Extract<Query<(RenderEntity, &Camera), With<Camera2d>>>,
|
||||
mut live_entities: Local<EntityHashSet>,
|
||||
cameras_2d: Extract<Query<(Entity, &Camera), With<Camera2d>>>,
|
||||
mut live_entities: Local<HashSet<RetainedViewEntity>>,
|
||||
) {
|
||||
live_entities.clear();
|
||||
|
||||
for (entity, camera) in &cameras_2d {
|
||||
for (main_entity, camera) in &cameras_2d {
|
||||
if !camera.is_active {
|
||||
continue;
|
||||
}
|
||||
transparent_2d_phases.insert_or_clear(entity);
|
||||
opaque_2d_phases.insert_or_clear(entity, GpuPreprocessingMode::None);
|
||||
alpha_mask_2d_phases.insert_or_clear(entity, GpuPreprocessingMode::None);
|
||||
|
||||
live_entities.insert(entity);
|
||||
// This is the main 2D camera, so we use the first subview index (0).
|
||||
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
|
||||
|
||||
transparent_2d_phases.insert_or_clear(retained_view_entity);
|
||||
opaque_2d_phases.insert_or_clear(retained_view_entity, GpuPreprocessingMode::None);
|
||||
alpha_mask_2d_phases.insert_or_clear(retained_view_entity, GpuPreprocessingMode::None);
|
||||
|
||||
live_entities.insert(retained_view_entity);
|
||||
}
|
||||
|
||||
// Clear out all dead views.
|
||||
@ -421,11 +452,13 @@ pub fn prepare_core_2d_depth_textures(
|
||||
render_device: Res<RenderDevice>,
|
||||
transparent_2d_phases: Res<ViewSortedRenderPhases<Transparent2d>>,
|
||||
opaque_2d_phases: Res<ViewBinnedRenderPhases<Opaque2d>>,
|
||||
views_2d: Query<(Entity, &ExtractedCamera, &Msaa), (With<Camera2d>,)>,
|
||||
views_2d: Query<(Entity, &ExtractedCamera, &ExtractedView, &Msaa), (With<Camera2d>,)>,
|
||||
) {
|
||||
let mut textures = <HashMap<_, _>>::default();
|
||||
for (view, camera, msaa) in &views_2d {
|
||||
if !opaque_2d_phases.contains_key(&view) || !transparent_2d_phases.contains_key(&view) {
|
||||
for (view, camera, extracted_view, msaa) in &views_2d {
|
||||
if !opaque_2d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
|| !transparent_2d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
{
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![expect(deprecated)]
|
||||
|
||||
use crate::{
|
||||
core_3d::graph::Core3d,
|
||||
tonemapping::{DebandDither, Tonemapping},
|
||||
@ -7,14 +5,11 @@ use crate::{
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
use bevy_render::{
|
||||
camera::{Camera, CameraMainTextureUsages, CameraRenderGraph, Exposure, Projection},
|
||||
camera::{Camera, CameraRenderGraph, Exposure, Projection},
|
||||
extract_component::ExtractComponent,
|
||||
primitives::Frustum,
|
||||
render_resource::{LoadOp, TextureUsages},
|
||||
sync_world::SyncToRenderWorld,
|
||||
view::{ColorGrading, Msaa, VisibleEntities},
|
||||
view::ColorGrading,
|
||||
};
|
||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A 3D camera component. Enables the main 3D render graph for a [`Camera`].
|
||||
@ -147,52 +142,3 @@ pub enum ScreenSpaceTransmissionQuality {
|
||||
/// `num_taps` = 32
|
||||
Ultra,
|
||||
}
|
||||
|
||||
/// The camera coordinate space is right-handed x-right, y-up, z-back.
|
||||
/// This means "forward" is -Z.
|
||||
#[derive(Bundle, Clone)]
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `Camera3d` component instead. Inserting it will now also insert the other components required by it automatically."
|
||||
)]
|
||||
pub struct Camera3dBundle {
|
||||
pub camera: Camera,
|
||||
pub camera_render_graph: CameraRenderGraph,
|
||||
pub projection: Projection,
|
||||
pub visible_entities: VisibleEntities,
|
||||
pub frustum: Frustum,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
pub camera_3d: Camera3d,
|
||||
pub tonemapping: Tonemapping,
|
||||
pub deband_dither: DebandDither,
|
||||
pub color_grading: ColorGrading,
|
||||
pub exposure: Exposure,
|
||||
pub main_texture_usages: CameraMainTextureUsages,
|
||||
pub msaa: Msaa,
|
||||
/// Marker component that indicates that its entity needs to be synchronized to the render world
|
||||
pub sync: SyncToRenderWorld,
|
||||
}
|
||||
|
||||
// NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference
|
||||
impl Default for Camera3dBundle {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
camera_render_graph: CameraRenderGraph::new(Core3d),
|
||||
camera: Default::default(),
|
||||
projection: Default::default(),
|
||||
visible_entities: Default::default(),
|
||||
frustum: Default::default(),
|
||||
transform: Default::default(),
|
||||
global_transform: Default::default(),
|
||||
camera_3d: Default::default(),
|
||||
tonemapping: Default::default(),
|
||||
color_grading: Default::default(),
|
||||
exposure: Default::default(),
|
||||
main_texture_usages: Default::default(),
|
||||
deband_dither: DebandDither::Enabled,
|
||||
msaa: Default::default(),
|
||||
sync: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::{
|
||||
core_3d::Opaque3d,
|
||||
skybox::{SkyboxBindGroup, SkyboxPipelineId},
|
||||
};
|
||||
use bevy_ecs::{entity::Entity, prelude::World, query::QueryItem};
|
||||
use bevy_ecs::{prelude::World, query::QueryItem};
|
||||
use bevy_render::{
|
||||
camera::ExtractedCamera,
|
||||
diagnostic::RecordDiagnostics,
|
||||
@ -10,11 +10,11 @@ use bevy_render::{
|
||||
render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
|
||||
render_resource::{CommandEncoderDescriptor, PipelineCache, RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::{ViewDepthTexture, ViewTarget, ViewUniformOffset},
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget, ViewUniformOffset},
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use tracing::info_span;
|
||||
|
||||
use super::AlphaMask3d;
|
||||
|
||||
@ -24,8 +24,8 @@ use super::AlphaMask3d;
|
||||
pub struct MainOpaquePass3dNode;
|
||||
impl ViewNode for MainOpaquePass3dNode {
|
||||
type ViewQuery = (
|
||||
Entity,
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static ViewTarget,
|
||||
&'static ViewDepthTexture,
|
||||
Option<&'static SkyboxPipelineId>,
|
||||
@ -38,8 +38,8 @@ impl ViewNode for MainOpaquePass3dNode {
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(
|
||||
view,
|
||||
camera,
|
||||
extracted_view,
|
||||
target,
|
||||
depth,
|
||||
skybox_pipeline,
|
||||
@ -55,9 +55,10 @@ impl ViewNode for MainOpaquePass3dNode {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let (Some(opaque_phase), Some(alpha_mask_phase)) =
|
||||
(opaque_phases.get(&view), alpha_mask_phases.get(&view))
|
||||
else {
|
||||
let (Some(opaque_phase), Some(alpha_mask_phase)) = (
|
||||
opaque_phases.get(&extracted_view.retained_view_entity),
|
||||
alpha_mask_phases.get(&extracted_view.retained_view_entity),
|
||||
) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
||||
@ -7,12 +7,12 @@ use bevy_render::{
|
||||
render_phase::ViewSortedRenderPhases,
|
||||
render_resource::{Extent3d, RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::{ViewDepthTexture, ViewTarget},
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use core::ops::Range;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use tracing::info_span;
|
||||
|
||||
/// A [`bevy_render::render_graph::Node`] that runs the [`Transmissive3d`]
|
||||
/// [`ViewSortedRenderPhases`].
|
||||
@ -22,6 +22,7 @@ pub struct MainTransmissivePass3dNode;
|
||||
impl ViewNode for MainTransmissivePass3dNode {
|
||||
type ViewQuery = (
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static Camera3d,
|
||||
&'static ViewTarget,
|
||||
Option<&'static ViewTransmissionTexture>,
|
||||
@ -32,7 +33,7 @@ impl ViewNode for MainTransmissivePass3dNode {
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext,
|
||||
(camera, camera_3d, target, transmission, depth): QueryItem<Self::ViewQuery>,
|
||||
(camera, view, camera_3d, target, transmission, depth): QueryItem<Self::ViewQuery>,
|
||||
world: &World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let view_entity = graph.view_entity();
|
||||
@ -43,7 +44,7 @@ impl ViewNode for MainTransmissivePass3dNode {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Some(transmissive_phase) = transmissive_phases.get(&view_entity) else {
|
||||
let Some(transmissive_phase) = transmissive_phases.get(&view.retained_view_entity) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
||||
@ -7,11 +7,11 @@ use bevy_render::{
|
||||
render_phase::ViewSortedRenderPhases,
|
||||
render_resource::{RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::{ViewDepthTexture, ViewTarget},
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use tracing::info_span;
|
||||
|
||||
/// A [`bevy_render::render_graph::Node`] that runs the [`Transparent3d`]
|
||||
/// [`ViewSortedRenderPhases`].
|
||||
@ -21,6 +21,7 @@ pub struct MainTransparentPass3dNode;
|
||||
impl ViewNode for MainTransparentPass3dNode {
|
||||
type ViewQuery = (
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static ViewTarget,
|
||||
&'static ViewDepthTexture,
|
||||
);
|
||||
@ -28,7 +29,7 @@ impl ViewNode for MainTransparentPass3dNode {
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext,
|
||||
(camera, target, depth): QueryItem<Self::ViewQuery>,
|
||||
(camera, view, target, depth): QueryItem<Self::ViewQuery>,
|
||||
world: &World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let view_entity = graph.view_entity();
|
||||
@ -39,7 +40,7 @@ impl ViewNode for MainTransparentPass3dNode {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let Some(transparent_phase) = transparent_phases.get(&view_entity) else {
|
||||
let Some(transparent_phase) = transparent_phases.get(&view.retained_view_entity) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
||||
@ -68,8 +68,8 @@ use core::ops::Range;
|
||||
use bevy_render::{
|
||||
batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
|
||||
mesh::allocator::SlabId,
|
||||
render_phase::PhaseItemBinKey,
|
||||
view::NoIndirectDrawing,
|
||||
render_phase::PhaseItemBatchSetKey,
|
||||
view::{NoIndirectDrawing, RetainedViewEntity},
|
||||
};
|
||||
pub use camera_3d::*;
|
||||
pub use main_opaque_pass_3d_node::*;
|
||||
@ -78,7 +78,7 @@ pub use main_transparent_pass_3d_node::*;
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_asset::UntypedAssetId;
|
||||
use bevy_color::LinearRgba;
|
||||
use bevy_ecs::{entity::EntityHashSet, prelude::*};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_image::BevyDefault;
|
||||
use bevy_math::FloatOrd;
|
||||
use bevy_render::{
|
||||
@ -101,8 +101,9 @@ use bevy_render::{
|
||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::{tracing::warn, HashMap};
|
||||
use bevy_utils::{HashMap, HashSet};
|
||||
use nonmax::NonMaxU32;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{
|
||||
core_3d::main_transmissive_pass_3d_node::MainTransmissivePass3dNode,
|
||||
@ -114,8 +115,8 @@ use crate::{
|
||||
dof::DepthOfFieldNode,
|
||||
prepass::{
|
||||
node::PrepassNode, AlphaMask3dPrepass, DeferredPrepass, DepthPrepass, MotionVectorPrepass,
|
||||
NormalPrepass, Opaque3dPrepass, OpaqueNoLightmap3dBinKey, ViewPrepassTextures,
|
||||
MOTION_VECTOR_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
|
||||
NormalPrepass, Opaque3dPrepass, OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey,
|
||||
ViewPrepassTextures, MOTION_VECTOR_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
|
||||
},
|
||||
skybox::SkyboxPlugin,
|
||||
tonemapping::TonemappingNode,
|
||||
@ -218,8 +219,13 @@ impl Plugin for Core3dPlugin {
|
||||
|
||||
/// Opaque 3D [`BinnedPhaseItem`]s.
|
||||
pub struct Opaque3d {
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: Opaque3dBatchSetKey,
|
||||
/// The key, which determines which can be batched.
|
||||
pub key: Opaque3dBinKey,
|
||||
pub bin_key: Opaque3dBinKey,
|
||||
/// An entity from which data will be fetched, including the mesh if
|
||||
/// applicable.
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
@ -264,17 +270,17 @@ pub struct Opaque3dBatchSetKey {
|
||||
pub lightmap_slab: Option<NonMaxU32>,
|
||||
}
|
||||
|
||||
impl PhaseItemBatchSetKey for Opaque3dBatchSetKey {
|
||||
fn indexed(&self) -> bool {
|
||||
self.index_slab.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// Data that must be identical in order to *batch* phase items together.
|
||||
///
|
||||
/// Note that a *batch set* (if multi-draw is in use) contains multiple batches.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Opaque3dBinKey {
|
||||
/// The key of the *batch set*.
|
||||
///
|
||||
/// As batches belong to a batch set, meshes in a batch must obviously be
|
||||
/// able to be placed in a single batch set.
|
||||
pub batch_set_key: Opaque3dBatchSetKey,
|
||||
|
||||
/// The asset that this phase item is associated with.
|
||||
///
|
||||
/// Normally, this is the ID of the mesh, but for non-mesh items it might be
|
||||
@ -282,14 +288,6 @@ pub struct Opaque3dBinKey {
|
||||
pub asset_id: UntypedAssetId,
|
||||
}
|
||||
|
||||
impl PhaseItemBinKey for Opaque3dBinKey {
|
||||
type BatchSetKey = Opaque3dBatchSetKey;
|
||||
|
||||
fn get_batch_set_key(&self) -> Option<Self::BatchSetKey> {
|
||||
Some(self.batch_set_key.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl PhaseItem for Opaque3d {
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
@ -303,7 +301,7 @@ impl PhaseItem for Opaque3d {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.batch_set_key.draw_function
|
||||
self.batch_set_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -326,17 +324,20 @@ impl PhaseItem for Opaque3d {
|
||||
}
|
||||
|
||||
impl BinnedPhaseItem for Opaque3d {
|
||||
type BatchSetKey = Opaque3dBatchSetKey;
|
||||
type BinKey = Opaque3dBinKey;
|
||||
|
||||
#[inline]
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
Opaque3d {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -347,12 +348,18 @@ impl BinnedPhaseItem for Opaque3d {
|
||||
impl CachedRenderPipelinePhaseItem for Opaque3d {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.batch_set_key.pipeline
|
||||
self.batch_set_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AlphaMask3d {
|
||||
pub key: OpaqueNoLightmap3dBinKey,
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
|
||||
/// The key, which determines which can be batched.
|
||||
pub bin_key: OpaqueNoLightmap3dBinKey,
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
@ -370,7 +377,7 @@ impl PhaseItem for AlphaMask3d {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.batch_set_key.draw_function
|
||||
self.batch_set_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -396,16 +403,19 @@ impl PhaseItem for AlphaMask3d {
|
||||
|
||||
impl BinnedPhaseItem for AlphaMask3d {
|
||||
type BinKey = OpaqueNoLightmap3dBinKey;
|
||||
type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
|
||||
|
||||
#[inline]
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -416,7 +426,7 @@ impl BinnedPhaseItem for AlphaMask3d {
|
||||
impl CachedRenderPipelinePhaseItem for AlphaMask3d {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.batch_set_key.pipeline
|
||||
self.batch_set_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,6 +437,9 @@ pub struct Transmissive3d {
|
||||
pub draw_function: DrawFunctionId,
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
/// Whether the mesh in question is indexed (uses an index buffer in
|
||||
/// addition to its vertex buffer).
|
||||
pub indexed: bool,
|
||||
}
|
||||
|
||||
impl PhaseItem for Transmissive3d {
|
||||
@ -490,6 +503,11 @@ impl SortedPhaseItem for Transmissive3d {
|
||||
fn sort(items: &mut [Self]) {
|
||||
radsort::sort_by_key(items, |item| item.distance);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn indexed(&self) -> bool {
|
||||
self.indexed
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedRenderPipelinePhaseItem for Transmissive3d {
|
||||
@ -506,6 +524,9 @@ pub struct Transparent3d {
|
||||
pub draw_function: DrawFunctionId,
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
/// Whether the mesh in question is indexed (uses an index buffer in
|
||||
/// addition to its vertex buffer).
|
||||
pub indexed: bool,
|
||||
}
|
||||
|
||||
impl PhaseItem for Transparent3d {
|
||||
@ -557,6 +578,11 @@ impl SortedPhaseItem for Transparent3d {
|
||||
fn sort(items: &mut [Self]) {
|
||||
radsort::sort_by_key(items, |item| item.distance);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn indexed(&self) -> bool {
|
||||
self.indexed
|
||||
}
|
||||
}
|
||||
|
||||
impl CachedRenderPipelinePhaseItem for Transparent3d {
|
||||
@ -571,13 +597,13 @@ pub fn extract_core_3d_camera_phases(
|
||||
mut alpha_mask_3d_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3d>>,
|
||||
mut transmissive_3d_phases: ResMut<ViewSortedRenderPhases<Transmissive3d>>,
|
||||
mut transparent_3d_phases: ResMut<ViewSortedRenderPhases<Transparent3d>>,
|
||||
cameras_3d: Extract<Query<(RenderEntity, &Camera, Has<NoIndirectDrawing>), With<Camera3d>>>,
|
||||
mut live_entities: Local<EntityHashSet>,
|
||||
cameras_3d: Extract<Query<(Entity, &Camera, Has<NoIndirectDrawing>), With<Camera3d>>>,
|
||||
mut live_entities: Local<HashSet<RetainedViewEntity>>,
|
||||
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
|
||||
) {
|
||||
live_entities.clear();
|
||||
|
||||
for (entity, camera, no_indirect_drawing) in &cameras_3d {
|
||||
for (main_entity, camera, no_indirect_drawing) in &cameras_3d {
|
||||
if !camera.is_active {
|
||||
continue;
|
||||
}
|
||||
@ -590,23 +616,25 @@ pub fn extract_core_3d_camera_phases(
|
||||
GpuPreprocessingMode::PreprocessingOnly
|
||||
});
|
||||
|
||||
opaque_3d_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
transmissive_3d_phases.insert_or_clear(entity);
|
||||
transparent_3d_phases.insert_or_clear(entity);
|
||||
// This is the main 3D camera, so use the first subview index (0).
|
||||
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
|
||||
|
||||
live_entities.insert(entity);
|
||||
opaque_3d_phases.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_phases.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
transmissive_3d_phases.insert_or_clear(retained_view_entity);
|
||||
transparent_3d_phases.insert_or_clear(retained_view_entity);
|
||||
|
||||
live_entities.insert(retained_view_entity);
|
||||
}
|
||||
|
||||
opaque_3d_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
alpha_mask_3d_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
transmissive_3d_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
transparent_3d_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
opaque_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
alpha_mask_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
transmissive_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
transparent_3d_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
}
|
||||
|
||||
// Extract the render phases for the prepass
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn extract_camera_prepass_phase(
|
||||
mut commands: Commands,
|
||||
mut opaque_3d_prepass_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
|
||||
@ -616,6 +644,7 @@ pub fn extract_camera_prepass_phase(
|
||||
cameras_3d: Extract<
|
||||
Query<
|
||||
(
|
||||
Entity,
|
||||
RenderEntity,
|
||||
&Camera,
|
||||
Has<NoIndirectDrawing>,
|
||||
@ -627,12 +656,13 @@ pub fn extract_camera_prepass_phase(
|
||||
With<Camera3d>,
|
||||
>,
|
||||
>,
|
||||
mut live_entities: Local<EntityHashSet>,
|
||||
mut live_entities: Local<HashSet<RetainedViewEntity>>,
|
||||
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
|
||||
) {
|
||||
live_entities.clear();
|
||||
|
||||
for (
|
||||
main_entity,
|
||||
entity,
|
||||
camera,
|
||||
no_indirect_drawing,
|
||||
@ -654,22 +684,27 @@ pub fn extract_camera_prepass_phase(
|
||||
GpuPreprocessingMode::PreprocessingOnly
|
||||
});
|
||||
|
||||
// This is the main 3D camera, so we use the first subview index (0).
|
||||
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
|
||||
|
||||
if depth_prepass || normal_prepass || motion_vector_prepass {
|
||||
opaque_3d_prepass_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_prepass_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
opaque_3d_prepass_phases.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_prepass_phases
|
||||
.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
} else {
|
||||
opaque_3d_prepass_phases.remove(&entity);
|
||||
alpha_mask_3d_prepass_phases.remove(&entity);
|
||||
opaque_3d_prepass_phases.remove(&retained_view_entity);
|
||||
alpha_mask_3d_prepass_phases.remove(&retained_view_entity);
|
||||
}
|
||||
|
||||
if deferred_prepass {
|
||||
opaque_3d_deferred_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_deferred_phases.insert_or_clear(entity, gpu_preprocessing_mode);
|
||||
opaque_3d_deferred_phases.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
alpha_mask_3d_deferred_phases
|
||||
.insert_or_clear(retained_view_entity, gpu_preprocessing_mode);
|
||||
} else {
|
||||
opaque_3d_deferred_phases.remove(&entity);
|
||||
alpha_mask_3d_deferred_phases.remove(&entity);
|
||||
opaque_3d_deferred_phases.remove(&retained_view_entity);
|
||||
alpha_mask_3d_deferred_phases.remove(&retained_view_entity);
|
||||
}
|
||||
live_entities.insert(entity);
|
||||
live_entities.insert(retained_view_entity);
|
||||
|
||||
commands
|
||||
.get_entity(entity)
|
||||
@ -680,13 +715,12 @@ pub fn extract_camera_prepass_phase(
|
||||
.insert_if(DeferredPrepass, || deferred_prepass);
|
||||
}
|
||||
|
||||
opaque_3d_prepass_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
alpha_mask_3d_prepass_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
opaque_3d_deferred_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
alpha_mask_3d_deferred_phases.retain(|entity, _| live_entities.contains(entity));
|
||||
opaque_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
alpha_mask_3d_prepass_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
opaque_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
alpha_mask_3d_deferred_phases.retain(|view_entity, _| live_entities.contains(view_entity));
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prepare_core_3d_depth_textures(
|
||||
mut commands: Commands,
|
||||
mut texture_cache: ResMut<TextureCache>,
|
||||
@ -698,17 +732,18 @@ pub fn prepare_core_3d_depth_textures(
|
||||
views_3d: Query<(
|
||||
Entity,
|
||||
&ExtractedCamera,
|
||||
&ExtractedView,
|
||||
Option<&DepthPrepass>,
|
||||
&Camera3d,
|
||||
&Msaa,
|
||||
)>,
|
||||
) {
|
||||
let mut render_target_usage = <HashMap<_, _>>::default();
|
||||
for (view, camera, depth_prepass, camera_3d, _msaa) in &views_3d {
|
||||
if !opaque_3d_phases.contains_key(&view)
|
||||
|| !alpha_mask_3d_phases.contains_key(&view)
|
||||
|| !transmissive_3d_phases.contains_key(&view)
|
||||
|| !transparent_3d_phases.contains_key(&view)
|
||||
for (_, camera, extracted_view, depth_prepass, camera_3d, _msaa) in &views_3d {
|
||||
if !opaque_3d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
|| !alpha_mask_3d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
|| !transmissive_3d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
|| !transparent_3d_phases.contains_key(&extracted_view.retained_view_entity)
|
||||
{
|
||||
continue;
|
||||
};
|
||||
@ -726,7 +761,7 @@ pub fn prepare_core_3d_depth_textures(
|
||||
}
|
||||
|
||||
let mut textures = <HashMap<_, _>>::default();
|
||||
for (entity, camera, _, camera_3d, msaa) in &views_3d {
|
||||
for (entity, camera, _, _, camera_3d, msaa) in &views_3d {
|
||||
let Some(physical_target_size) = camera.physical_target_size else {
|
||||
continue;
|
||||
};
|
||||
@ -777,7 +812,6 @@ pub struct ViewTransmissionTexture {
|
||||
pub sampler: Sampler,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prepare_core_3d_transmission_textures(
|
||||
mut commands: Commands,
|
||||
mut texture_cache: ResMut<TextureCache>,
|
||||
@ -790,14 +824,15 @@ pub fn prepare_core_3d_transmission_textures(
|
||||
) {
|
||||
let mut textures = <HashMap<_, _>>::default();
|
||||
for (entity, camera, camera_3d, view) in &views_3d {
|
||||
if !opaque_3d_phases.contains_key(&entity)
|
||||
|| !alpha_mask_3d_phases.contains_key(&entity)
|
||||
|| !transparent_3d_phases.contains_key(&entity)
|
||||
if !opaque_3d_phases.contains_key(&view.retained_view_entity)
|
||||
|| !alpha_mask_3d_phases.contains_key(&view.retained_view_entity)
|
||||
|| !transparent_3d_phases.contains_key(&view.retained_view_entity)
|
||||
{
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(transmissive_3d_phase) = transmissive_3d_phases.get(&entity) else {
|
||||
let Some(transmissive_3d_phase) = transmissive_3d_phases.get(&view.retained_view_entity)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@ -877,7 +912,6 @@ pub fn check_msaa(mut deferred_views: Query<&mut Msaa, (With<Camera>, With<Defer
|
||||
}
|
||||
|
||||
// Prepares the textures used by the prepass
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prepare_prepass_textures(
|
||||
mut commands: Commands,
|
||||
mut texture_cache: ResMut<TextureCache>,
|
||||
@ -889,6 +923,7 @@ pub fn prepare_prepass_textures(
|
||||
views_3d: Query<(
|
||||
Entity,
|
||||
&ExtractedCamera,
|
||||
&ExtractedView,
|
||||
&Msaa,
|
||||
Has<DepthPrepass>,
|
||||
Has<NormalPrepass>,
|
||||
@ -904,6 +939,7 @@ pub fn prepare_prepass_textures(
|
||||
for (
|
||||
entity,
|
||||
camera,
|
||||
view,
|
||||
msaa,
|
||||
depth_prepass,
|
||||
normal_prepass,
|
||||
@ -911,10 +947,10 @@ pub fn prepare_prepass_textures(
|
||||
deferred_prepass,
|
||||
) in &views_3d
|
||||
{
|
||||
if !opaque_3d_prepass_phases.contains_key(&entity)
|
||||
&& !alpha_mask_3d_prepass_phases.contains_key(&entity)
|
||||
&& !opaque_3d_deferred_phases.contains_key(&entity)
|
||||
&& !alpha_mask_3d_deferred_phases.contains_key(&entity)
|
||||
if !opaque_3d_prepass_phases.contains_key(&view.retained_view_entity)
|
||||
&& !alpha_mask_3d_prepass_phases.contains_key(&view.retained_view_entity)
|
||||
&& !opaque_3d_deferred_phases.contains_key(&view.retained_view_entity)
|
||||
&& !alpha_mask_3d_deferred_phases.contains_key(&view.retained_view_entity)
|
||||
{
|
||||
continue;
|
||||
};
|
||||
|
||||
@ -3,8 +3,7 @@ pub mod node;
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
use crate::core_3d::Opaque3dBinKey;
|
||||
use crate::prepass::OpaqueNoLightmap3dBinKey;
|
||||
use crate::prepass::{OpaqueNoLightmap3dBatchSetKey, OpaqueNoLightmap3dBinKey};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render::sync_world::MainEntity;
|
||||
use bevy_render::{
|
||||
@ -26,7 +25,13 @@ pub const DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT: TextureFormat = TextureFormat:
|
||||
/// Used to render all 3D meshes with materials that have no transparency.
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct Opaque3dDeferred {
|
||||
pub key: Opaque3dBinKey,
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
|
||||
/// Information that separates items into bins.
|
||||
pub bin_key: OpaqueNoLightmap3dBinKey,
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
@ -44,7 +49,7 @@ impl PhaseItem for Opaque3dDeferred {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.batch_set_key.draw_function
|
||||
self.batch_set_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -69,17 +74,20 @@ impl PhaseItem for Opaque3dDeferred {
|
||||
}
|
||||
|
||||
impl BinnedPhaseItem for Opaque3dDeferred {
|
||||
type BinKey = Opaque3dBinKey;
|
||||
type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
|
||||
type BinKey = OpaqueNoLightmap3dBinKey;
|
||||
|
||||
#[inline]
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -90,7 +98,7 @@ impl BinnedPhaseItem for Opaque3dDeferred {
|
||||
impl CachedRenderPipelinePhaseItem for Opaque3dDeferred {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.batch_set_key.pipeline
|
||||
self.batch_set_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +108,13 @@ impl CachedRenderPipelinePhaseItem for Opaque3dDeferred {
|
||||
///
|
||||
/// Used to render all meshes with a material with an alpha mask.
|
||||
pub struct AlphaMask3dDeferred {
|
||||
pub key: OpaqueNoLightmap3dBinKey,
|
||||
/// Determines which objects can be placed into a *batch set*.
|
||||
///
|
||||
/// Objects in a single batch set can potentially be multi-drawn together,
|
||||
/// if it's enabled and the current platform supports it.
|
||||
pub batch_set_key: OpaqueNoLightmap3dBatchSetKey,
|
||||
/// Information that separates items into bins.
|
||||
pub bin_key: OpaqueNoLightmap3dBinKey,
|
||||
pub representative_entity: (Entity, MainEntity),
|
||||
pub batch_range: Range<u32>,
|
||||
pub extra_index: PhaseItemExtraIndex,
|
||||
@ -119,7 +133,7 @@ impl PhaseItem for AlphaMask3dDeferred {
|
||||
|
||||
#[inline]
|
||||
fn draw_function(&self) -> DrawFunctionId {
|
||||
self.key.batch_set_key.draw_function
|
||||
self.batch_set_key.draw_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -144,16 +158,19 @@ impl PhaseItem for AlphaMask3dDeferred {
|
||||
}
|
||||
|
||||
impl BinnedPhaseItem for AlphaMask3dDeferred {
|
||||
type BatchSetKey = OpaqueNoLightmap3dBatchSetKey;
|
||||
type BinKey = OpaqueNoLightmap3dBinKey;
|
||||
|
||||
fn new(
|
||||
key: Self::BinKey,
|
||||
batch_set_key: Self::BatchSetKey,
|
||||
bin_key: Self::BinKey,
|
||||
representative_entity: (Entity, MainEntity),
|
||||
batch_range: Range<u32>,
|
||||
extra_index: PhaseItemExtraIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
key,
|
||||
batch_set_key,
|
||||
bin_key,
|
||||
representative_entity,
|
||||
batch_range,
|
||||
extra_index,
|
||||
@ -164,6 +181,6 @@ impl BinnedPhaseItem for AlphaMask3dDeferred {
|
||||
impl CachedRenderPipelinePhaseItem for AlphaMask3dDeferred {
|
||||
#[inline]
|
||||
fn cached_pipeline(&self) -> CachedRenderPipelineId {
|
||||
self.key.batch_set_key.pipeline
|
||||
self.batch_set_key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_render::render_graph::ViewNode;
|
||||
|
||||
use bevy_render::view::ExtractedView;
|
||||
use bevy_render::{
|
||||
camera::ExtractedCamera,
|
||||
render_graph::{NodeRunError, RenderGraphContext},
|
||||
@ -9,9 +10,9 @@ use bevy_render::{
|
||||
renderer::RenderContext,
|
||||
view::ViewDepthTexture,
|
||||
};
|
||||
use bevy_utils::tracing::error;
|
||||
use tracing::error;
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
use tracing::info_span;
|
||||
|
||||
use crate::prepass::ViewPrepassTextures;
|
||||
|
||||
@ -25,8 +26,8 @@ pub struct DeferredGBufferPrepassNode;
|
||||
|
||||
impl ViewNode for DeferredGBufferPrepassNode {
|
||||
type ViewQuery = (
|
||||
Entity,
|
||||
&'static ExtractedCamera,
|
||||
&'static ExtractedView,
|
||||
&'static ViewDepthTexture,
|
||||
&'static ViewPrepassTextures,
|
||||
);
|
||||
@ -35,7 +36,10 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(view, camera, view_depth_texture, view_prepass_textures): QueryItem<'w, Self::ViewQuery>,
|
||||
(camera, extracted_view, view_depth_texture, view_prepass_textures): QueryItem<
|
||||
'w,
|
||||
Self::ViewQuery,
|
||||
>,
|
||||
world: &'w World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let (Some(opaque_deferred_phases), Some(alpha_mask_deferred_phases)) = (
|
||||
@ -46,8 +50,8 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
||||
};
|
||||
|
||||
let (Some(opaque_deferred_phase), Some(alpha_mask_deferred_phase)) = (
|
||||
opaque_deferred_phases.get(&view),
|
||||
alpha_mask_deferred_phases.get(&view),
|
||||
opaque_deferred_phases.get(&extracted_view.retained_view_entity),
|
||||
alpha_mask_deferred_phases.get(&extracted_view.retained_view_entity),
|
||||
) else {
|
||||
return Ok(());
|
||||
};
|
||||
@ -143,7 +147,8 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
||||
}
|
||||
|
||||
// Opaque draws
|
||||
if !opaque_deferred_phase.batchable_mesh_keys.is_empty()
|
||||
if !opaque_deferred_phase.multidrawable_mesh_keys.is_empty()
|
||||
|| !opaque_deferred_phase.batchable_mesh_keys.is_empty()
|
||||
|| !opaque_deferred_phase.unbatchable_mesh_keys.is_empty()
|
||||
{
|
||||
#[cfg(feature = "trace")]
|
||||
|
||||
@ -56,8 +56,9 @@ use bevy_render::{
|
||||
},
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::{info_once, prelude::default, warn_once};
|
||||
use bevy_utils::{default, once};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::{
|
||||
core_3d::{
|
||||
@ -119,9 +120,6 @@ pub struct DepthOfField {
|
||||
pub max_depth: f32,
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.15.0", note = "Renamed to `DepthOfField`")]
|
||||
pub type DepthOfFieldSettings = DepthOfField;
|
||||
|
||||
/// Controls the appearance of the effect.
|
||||
#[derive(Clone, Copy, Default, PartialEq, Debug, Reflect)]
|
||||
#[reflect(Default, PartialEq)]
|
||||
@ -384,7 +382,9 @@ impl ViewNode for DepthOfFieldNode {
|
||||
auxiliary_dof_texture,
|
||||
view_bind_group_layouts.dual_input.as_ref(),
|
||||
) else {
|
||||
warn_once!("Should have created the auxiliary depth of field texture by now");
|
||||
once!(warn!(
|
||||
"Should have created the auxiliary depth of field texture by now"
|
||||
));
|
||||
continue;
|
||||
};
|
||||
render_context.render_device().create_bind_group(
|
||||
@ -426,7 +426,9 @@ impl ViewNode for DepthOfFieldNode {
|
||||
// `prepare_auxiliary_depth_of_field_textures``.
|
||||
if pipeline_render_info.is_dual_output {
|
||||
let Some(auxiliary_dof_texture) = auxiliary_dof_texture else {
|
||||
warn_once!("Should have created the auxiliary depth of field texture by now");
|
||||
once!(warn!(
|
||||
"Should have created the auxiliary depth of field texture by now"
|
||||
));
|
||||
continue;
|
||||
};
|
||||
color_attachments.push(Some(RenderPassColorAttachment {
|
||||
@ -818,9 +820,9 @@ fn extract_depth_of_field_settings(
|
||||
mut query: Extract<Query<(RenderEntity, &DepthOfField, &Projection)>>,
|
||||
) {
|
||||
if !DEPTH_TEXTURE_SAMPLING_SUPPORTED {
|
||||
info_once!(
|
||||
once!(info!(
|
||||
"Disabling depth of field on this platform because depth textures aren't supported correctly"
|
||||
);
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -33,11 +33,9 @@ pub use skybox::Skybox;
|
||||
///
|
||||
/// Expect bugs, missing features, compatibility issues, low performance, and/or future breaking changes.
|
||||
pub mod experimental {
|
||||
#[expect(deprecated)]
|
||||
pub mod taa {
|
||||
pub use crate::taa::{
|
||||
TemporalAntiAliasBundle, TemporalAntiAliasNode, TemporalAntiAliasPlugin,
|
||||
TemporalAntiAliasSettings, TemporalAntiAliasing,
|
||||
TemporalAntiAliasNode, TemporalAntiAliasPlugin, TemporalAntiAliasing,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -45,13 +43,9 @@ pub mod experimental {
|
||||
/// The core pipeline prelude.
|
||||
///
|
||||
/// This includes the most common types in this crate, re-exported for your convenience.
|
||||
#[expect(deprecated)]
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
core_2d::{Camera2d, Camera2dBundle},
|
||||
core_3d::{Camera3d, Camera3dBundle},
|
||||
};
|
||||
pub use crate::{core_2d::Camera2d, core_3d::Camera3d};
|
||||
}
|
||||
|
||||
use crate::{
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
//!
|
||||
//! Add the [`MotionBlur`] component to a camera to enable motion blur.
|
||||
|
||||
#![expect(deprecated)]
|
||||
|
||||
use crate::{
|
||||
core_3d::graph::{Core3d, Node3d},
|
||||
prepass::{DepthPrepass, MotionVectorPrepass},
|
||||
@ -11,7 +9,6 @@ use crate::{
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, Handle};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
component::{require, Component},
|
||||
query::With,
|
||||
reflect::ReflectComponent,
|
||||
@ -29,18 +26,6 @@ use bevy_render::{
|
||||
pub mod node;
|
||||
pub mod pipeline;
|
||||
|
||||
/// Adds [`MotionBlur`] and the required depth and motion vector prepasses to a camera entity.
|
||||
#[derive(Bundle, Default)]
|
||||
#[deprecated(
|
||||
since = "0.15.0",
|
||||
note = "Use the `MotionBlur` component instead. Inserting it will now also insert the other components required by it automatically."
|
||||
)]
|
||||
pub struct MotionBlurBundle {
|
||||
pub motion_blur: MotionBlur,
|
||||
pub depth_prepass: DepthPrepass,
|
||||
pub motion_vector_prepass: MotionVectorPrepass,
|
||||
}
|
||||
|
||||
/// A component that enables and configures motion blur when added to a camera.
|
||||
///
|
||||
/// Motion blur is an effect that simulates how moving objects blur as they change position during
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user