diff --git a/.github/example-run/headless_defaults.ron b/.github/example-run/headless_defaults.ron new file mode 100644 index 0000000000000..22e43495b5e42 --- /dev/null +++ b/.github/example-run/headless_defaults.ron @@ -0,0 +1,3 @@ +( + exit_after: Some(100) +) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4b3241ec69db0..722f3aabe3aa6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,7 +11,7 @@ ## Changelog -> This section is optional. If this was a trivial fix, or has no externally-visible impact, feel free to skip this section. +> This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section. - What changed as a result of this PR? - If applicable, organize changes under "Added", "Changed", or "Fixed" sub-headings @@ -20,7 +20,7 @@ ## Migration Guide -> This section is optional +> This section is optional. If there are no breaking changes, you can delete this section. - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 878df8f026c31..428b0e359fc69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -274,13 +274,13 @@ jobs: toolchain: stable - name: Build bevy run: | - cargo build --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome" + cargo build --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome,bevy_audio,vorbis" - name: Run examples run: | for example in .github/example-run/*.ron; do example_name=`basename $example .ron` echo "running $example_name - "`date` - time CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome" + time CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --no-default-features --features "bevy_dynamic_plugin,bevy_gilrs,bevy_gltf,bevy_winit,render,png,hdr,x11,bevy_ci_testing,trace,trace_chrome,bevy_audio,vorbis" sleep 10 done zip traces.zip trace*.json diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e68f2251dff76..3ba82d145d297 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -50,7 +50,7 @@ jobs: touch target/doc/.nojekyll - name: Deploy - uses: JamesIves/github-pages-deploy-action@4.1.7 + uses: JamesIves/github-pages-deploy-action@v4.3.0 with: branch: gh-pages folder: target/doc diff --git a/CHANGELOG.md b/CHANGELOG.md index 9275603a37875..a70b76da9460d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,294 @@ current changes on git with [previous release tags][git_tag_comparison]. [git_tag_comparison]: https://github.com/bevyengine/bevy/compare/v0.6.0...main +## Version 0.7.0 (2022-04-15) + +### Added + +- [Mesh Skinning][4238] +- [Animation Player][4375] +- [Gltf animations][3751] +- [Mesh vertex buffer layouts][3959] +- [Render to a texture][3412] +- [KTX2/DDS/.basis compressed texture support][3884] +- [Audio control - play, pause, volume, speed, loop][3948] +- [Auto-label function systems with SystemTypeIdLabel][4224] +- [Query::get_many][4298] +- [Dynamic light clusters][3968] +- [Always update clusters and remove per-frame allocations][4169] +- [`ParamSet` for conflicting `SystemParam`:s][2765] +- [default() shorthand][4071] +- [use marker components for cameras instead of name strings][3635] +- [Implement `WorldQuery` derive macro][2713] +- [Implement AnyOf queries][2889] +- [Compute Pipeline Specialization][3979] +- [Make get_resource (and friends) infallible][4047] +- [bevy_pbr: Support flipping tangent space normal map y for DirectX normal maps][4433] +- [Faster view frustum culling][4181] +- [Use storage buffers for clustered forward point lights][3989] +- [Add &World as SystemParam][2923] +- [Add text wrapping support to Text2d][4347] +- [Scene Viewer to display glTF files][4183] +- [Internal Asset Hot Reloading][3966] +- [Add FocusPolicy to NodeBundle and ImageBundle][3952] +- [Allow iter combinations on queries with filters][3656] +- [bevy_render: Support overriding wgpu features and limits][3912] +- [bevy_render: Use RenderDevice to get limits/features and expose AdapterInfo][3931] +- [Reduce power usage with configurable event loop][3974] +- [can specify an anchor for a sprite][3463] +- [Implement len and is_empty for EventReaders][2969] +- [Add more FromWorld implementations][3945] +- [Add cart's fork of ecs_bench_suite][4225] +- [bevy_derive: Add derives for `Deref` and `DerefMut`][4328] +- [Add clear_schedule][3941] +- [Add Query::contains][3090] +- [bevy_render: Support removal of nodes, edges, subgraphs][3048] +- [Implement init_resource for `Commands` and `World`][3079] +- [Added method to restart the current state][3328] +- [Simplify sending empty events][2935] +- [impl Command for `impl FnOnce(&mut World)`][2996] +- [Useful error message when two assets have the save UUID][3739] +- [bevy_asset: Add AssetServerSettings watch_for_changes member][3643] +- [Add conversio from Color to u32][4088] +- [Introduce `SystemLabel`'s for `RenderAssetPlugin`, and change `Image` preparation system to run before others][3917] +- [Add a helper for storage buffers similar to `UniformVec`][4079] +- [StandardMaterial: expose a cull_mode option][3982] +- [Expose draw indirect][4056] +- [Add view transform to view uniform][3885] +- [Add a size method on Image.][3696] +- [add Visibility for lights][3958] +- [bevy_render: Provide a way to opt-out of the built-in frustum culling][3711] +- [use error scope to handle errors on shader module creation][3675] +- [include sources in shader validation error][3724] +- [insert the gltf mesh name on the entity if there is one][4119] +- [expose extras from gltf nodes][2154] +- [gltf: add a name to nodes without names][4396] +- [Enable drag-and-drop events on windows][3772] +- [Add transform hierarchy stress test][4170] +- [Add TransformBundle][3054] +- [Add Transform::rotate_around method][3107] +- [example on how to create an animation in code][4399] +- [Add examples for Transforms][2441] +- [Add mouse grab example][4114] +- [examples: add screenspace texture shader example][4063] +- [Add generic systems example][2636] +- [add examples on how to have a data source running in another thread / in a task pool thread][2915] +- [Simple 2d rotation example][3065] +- [Add move sprite example.][2414] +- [add an example using UI & states to create a game menu][2960] +- [CI runs `cargo miri test -p bevy_ecs`][4310] +- [Tracy spans around main 3D passes][4182] +- [Add automatic docs deployment to GitHub Pages][3535] + +### Changed + +- [Proper prehashing][3963] +- [Move import_path definitions into shader source][3976] +- [Make `System` responsible for updating its own archetypes][4115] +- [Some small changes related to run criteria piping][3923] +- [Remove unnecessary system labels][4340] +- [Increment last event count on next instead of iter][2382] +- [Obviate the need for `RunSystem`, and remove it][3817] +- [Cleanup some things which shouldn't be components][2982] +- [Remove the config api][3633] +- [Deprecate `.system`][3302] +- [Hide docs for concrete impls of Fetch, FetchState, and SystemParamState][4250] +- [Move the CoreStage::Startup to a seperate StartupSchedule label][2434] +- [`iter_mut` on Assets: send modified event only when asset is iterated over][3565] +- [check if resource for asset already exists before adding it][3560] +- [bevy_render: Batch insertion for prepare_uniform_components][4179] +- [Change default `ColorMaterial` color to white][3981] +- [bevy_render: Only auto-disable mappable primary buffers for discrete GPUs][3803] +- [bevy_render: Do not automatically enable MAPPABLE_PRIMARY_BUFFERS][3698] +- [increase the maximum number of point lights with shadows to the max supported by the device][4435] +- [perf: only recalculate frusta of changed lights][4086] +- [bevy_pbr: Optimize assign_lights_to_clusters][3984] +- [improve error messages for render graph runner][3930] +- [Skinned extraction speedup][4428] +- [Sprites - keep color as 4 f32][4361] +- [Change scaling mode to FixedHorizontal][4055] +- [Replace VSync with PresentMode][3812] +- [do not set cursor grab on window creation if not asked for][3617] +- [bevy_transform: Use Changed in the query for much faster transform_propagate_system][4180] +- [Split bevy_hierarchy out from bevy_transform][4168] +- [Make transform builder methods const][3045] +- [many_cubes: Add a cube pattern suitable for benchmarking culling changes][4126] +- [Make many_cubes example more interesting][4015] +- [Run tests (including doc tests) in `cargo run -p ci` command][3849] +- [Use more ergonomic span syntax][4246] + +### Fixed + +- [Remove unsound lifetime annotations on `EntityMut`][4096] +- [Remove unsound lifetime annotations on `Query` methods][4243] +- [Remove `World::components_mut`][4092] +- [unsafeify `World::entities_mut`][4093] +- [Use ManuallyDrop instead of forget in insert_resource_with_id][2947] +- [Backport soundness fix][3685] +- [Fix clicked UI nodes getting reset when hovering child nodes][4194] +- [Fix ui interactions when cursor disappears suddenly][3926] +- [Fix node update][3785] +- [Fix derive(SystemParam) macro][4400] +- [SystemParam Derive fixes][2838] +- [Do not crash if RenderDevice doesn't exist][4427] +- [Fixed case of R == G, following original conversion formula][4383] +- [Fixed the frustum-sphere collision and added tests][4035] +- [bevy_render: Fix Quad flip][3741] +- [Fix HDR asset support][3795] +- [fix cluster tiling calculations][4148] +- [bevy_pbr: Do not panic when more than 256 point lights are added the scene][3697] +- [fix issues with too many point lights][3916] +- [shader preprocessor - do not import if scope is not valid][4012] +- [support all line endings in shader preprocessor][3603] +- [Fix animation: shadow and wireframe support][4367] +- [add AnimationPlayer component only on scene roots that are also animation roots][4417] +- [Fix loading non-TriangleList meshes without normals in gltf loader][4376] +- [gltf-loader: disable backface culling if material is double-sided][4270] +- [Fix glTF perspective camera projection][4006] +- [fix mul_vec3 transformation order: should be scale -> rotate -> translate][3811] + +[2154]: https://github.com/bevyengine/bevy/pull/2154 +[2382]: https://github.com/bevyengine/bevy/pull/2382 +[2414]: https://github.com/bevyengine/bevy/pull/2414 +[2434]: https://github.com/bevyengine/bevy/pull/2434 +[2441]: https://github.com/bevyengine/bevy/pull/2441 +[2636]: https://github.com/bevyengine/bevy/pull/2636 +[2713]: https://github.com/bevyengine/bevy/pull/2713 +[2765]: https://github.com/bevyengine/bevy/pull/2765 +[2838]: https://github.com/bevyengine/bevy/pull/2838 +[2889]: https://github.com/bevyengine/bevy/pull/2889 +[2915]: https://github.com/bevyengine/bevy/pull/2915 +[2923]: https://github.com/bevyengine/bevy/pull/2923 +[2935]: https://github.com/bevyengine/bevy/pull/2935 +[2947]: https://github.com/bevyengine/bevy/pull/2947 +[2960]: https://github.com/bevyengine/bevy/pull/2960 +[2969]: https://github.com/bevyengine/bevy/pull/2969 +[2982]: https://github.com/bevyengine/bevy/pull/2982 +[2996]: https://github.com/bevyengine/bevy/pull/2996 +[3045]: https://github.com/bevyengine/bevy/pull/3045 +[3048]: https://github.com/bevyengine/bevy/pull/3048 +[3054]: https://github.com/bevyengine/bevy/pull/3054 +[3065]: https://github.com/bevyengine/bevy/pull/3065 +[3079]: https://github.com/bevyengine/bevy/pull/3079 +[3090]: https://github.com/bevyengine/bevy/pull/3090 +[3107]: https://github.com/bevyengine/bevy/pull/3107 +[3302]: https://github.com/bevyengine/bevy/pull/3302 +[3328]: https://github.com/bevyengine/bevy/pull/3328 +[3412]: https://github.com/bevyengine/bevy/pull/3412 +[3463]: https://github.com/bevyengine/bevy/pull/3463 +[3535]: https://github.com/bevyengine/bevy/pull/3535 +[3560]: https://github.com/bevyengine/bevy/pull/3560 +[3565]: https://github.com/bevyengine/bevy/pull/3565 +[3603]: https://github.com/bevyengine/bevy/pull/3603 +[3617]: https://github.com/bevyengine/bevy/pull/3617 +[3633]: https://github.com/bevyengine/bevy/pull/3633 +[3635]: https://github.com/bevyengine/bevy/pull/3635 +[3643]: https://github.com/bevyengine/bevy/pull/3643 +[3656]: https://github.com/bevyengine/bevy/pull/3656 +[3675]: https://github.com/bevyengine/bevy/pull/3675 +[3685]: https://github.com/bevyengine/bevy/pull/3685 +[3696]: https://github.com/bevyengine/bevy/pull/3696 +[3697]: https://github.com/bevyengine/bevy/pull/3697 +[3698]: https://github.com/bevyengine/bevy/pull/3698 +[3711]: https://github.com/bevyengine/bevy/pull/3711 +[3724]: https://github.com/bevyengine/bevy/pull/3724 +[3739]: https://github.com/bevyengine/bevy/pull/3739 +[3741]: https://github.com/bevyengine/bevy/pull/3741 +[3751]: https://github.com/bevyengine/bevy/pull/3751 +[3772]: https://github.com/bevyengine/bevy/pull/3772 +[3785]: https://github.com/bevyengine/bevy/pull/3785 +[3795]: https://github.com/bevyengine/bevy/pull/3795 +[3803]: https://github.com/bevyengine/bevy/pull/3803 +[3811]: https://github.com/bevyengine/bevy/pull/3811 +[3812]: https://github.com/bevyengine/bevy/pull/3812 +[3817]: https://github.com/bevyengine/bevy/pull/3817 +[3849]: https://github.com/bevyengine/bevy/pull/3849 +[3884]: https://github.com/bevyengine/bevy/pull/3884 +[3885]: https://github.com/bevyengine/bevy/pull/3885 +[3912]: https://github.com/bevyengine/bevy/pull/3912 +[3916]: https://github.com/bevyengine/bevy/pull/3916 +[3917]: https://github.com/bevyengine/bevy/pull/3917 +[3923]: https://github.com/bevyengine/bevy/pull/3923 +[3926]: https://github.com/bevyengine/bevy/pull/3926 +[3930]: https://github.com/bevyengine/bevy/pull/3930 +[3931]: https://github.com/bevyengine/bevy/pull/3931 +[3941]: https://github.com/bevyengine/bevy/pull/3941 +[3945]: https://github.com/bevyengine/bevy/pull/3945 +[3948]: https://github.com/bevyengine/bevy/pull/3948 +[3952]: https://github.com/bevyengine/bevy/pull/3952 +[3958]: https://github.com/bevyengine/bevy/pull/3958 +[3959]: https://github.com/bevyengine/bevy/pull/3959 +[3963]: https://github.com/bevyengine/bevy/pull/3963 +[3966]: https://github.com/bevyengine/bevy/pull/3966 +[3968]: https://github.com/bevyengine/bevy/pull/3968 +[3974]: https://github.com/bevyengine/bevy/pull/3974 +[3976]: https://github.com/bevyengine/bevy/pull/3976 +[3979]: https://github.com/bevyengine/bevy/pull/3979 +[3981]: https://github.com/bevyengine/bevy/pull/3981 +[3982]: https://github.com/bevyengine/bevy/pull/3982 +[3984]: https://github.com/bevyengine/bevy/pull/3984 +[3989]: https://github.com/bevyengine/bevy/pull/3989 +[4006]: https://github.com/bevyengine/bevy/pull/4006 +[4012]: https://github.com/bevyengine/bevy/pull/4012 +[4015]: https://github.com/bevyengine/bevy/pull/4015 +[4035]: https://github.com/bevyengine/bevy/pull/4035 +[4047]: https://github.com/bevyengine/bevy/pull/4047 +[4055]: https://github.com/bevyengine/bevy/pull/4055 +[4056]: https://github.com/bevyengine/bevy/pull/4056 +[4063]: https://github.com/bevyengine/bevy/pull/4063 +[4071]: https://github.com/bevyengine/bevy/pull/4071 +[4079]: https://github.com/bevyengine/bevy/pull/4079 +[4086]: https://github.com/bevyengine/bevy/pull/4086 +[4088]: https://github.com/bevyengine/bevy/pull/4088 +[4092]: https://github.com/bevyengine/bevy/pull/4092 +[4093]: https://github.com/bevyengine/bevy/pull/4093 +[4096]: https://github.com/bevyengine/bevy/pull/4096 +[4114]: https://github.com/bevyengine/bevy/pull/4114 +[4115]: https://github.com/bevyengine/bevy/pull/4115 +[4119]: https://github.com/bevyengine/bevy/pull/4119 +[4126]: https://github.com/bevyengine/bevy/pull/4126 +[4148]: https://github.com/bevyengine/bevy/pull/4148 +[4168]: https://github.com/bevyengine/bevy/pull/4168 +[4169]: https://github.com/bevyengine/bevy/pull/4169 +[4170]: https://github.com/bevyengine/bevy/pull/4170 +[4179]: https://github.com/bevyengine/bevy/pull/4179 +[4180]: https://github.com/bevyengine/bevy/pull/4180 +[4181]: https://github.com/bevyengine/bevy/pull/4181 +[4182]: https://github.com/bevyengine/bevy/pull/4182 +[4183]: https://github.com/bevyengine/bevy/pull/4183 +[4194]: https://github.com/bevyengine/bevy/pull/4194 +[4224]: https://github.com/bevyengine/bevy/pull/4224 +[4225]: https://github.com/bevyengine/bevy/pull/4225 +[4238]: https://github.com/bevyengine/bevy/pull/4238 +[4243]: https://github.com/bevyengine/bevy/pull/4243 +[4246]: https://github.com/bevyengine/bevy/pull/4246 +[4250]: https://github.com/bevyengine/bevy/pull/4250 +[4252]: https://github.com/bevyengine/bevy/pull/4252 +[4270]: https://github.com/bevyengine/bevy/pull/4270 +[4298]: https://github.com/bevyengine/bevy/pull/4298 +[4310]: https://github.com/bevyengine/bevy/pull/4310 +[4328]: https://github.com/bevyengine/bevy/pull/4328 +[4332]: https://github.com/bevyengine/bevy/pull/4332 +[4340]: https://github.com/bevyengine/bevy/pull/4340 +[4347]: https://github.com/bevyengine/bevy/pull/4347 +[4361]: https://github.com/bevyengine/bevy/pull/4361 +[4367]: https://github.com/bevyengine/bevy/pull/4367 +[4375]: https://github.com/bevyengine/bevy/pull/4375 +[4376]: https://github.com/bevyengine/bevy/pull/4376 +[4383]: https://github.com/bevyengine/bevy/pull/4383 +[4396]: https://github.com/bevyengine/bevy/pull/4396 +[4399]: https://github.com/bevyengine/bevy/pull/4399 +[4400]: https://github.com/bevyengine/bevy/pull/4400 +[4403]: https://github.com/bevyengine/bevy/pull/4403 +[4405]: https://github.com/bevyengine/bevy/pull/4405 +[4417]: https://github.com/bevyengine/bevy/pull/4417 +[4420]: https://github.com/bevyengine/bevy/pull/4420 +[4426]: https://github.com/bevyengine/bevy/pull/4426 +[4427]: https://github.com/bevyengine/bevy/pull/4427 +[4428]: https://github.com/bevyengine/bevy/pull/4428 +[4433]: https://github.com/bevyengine/bevy/pull/4433 +[4435]: https://github.com/bevyengine/bevy/pull/4435 + ## Version 0.6.0 (2022-01-08) ### Added diff --git a/Cargo.toml b/Cargo.toml index 74927f5531ee7..3f5c13b5109b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" categories = ["game-engines", "graphics", "gui", "rendering"] description = "A refreshingly simple data-driven game engine and app framework" @@ -104,11 +104,11 @@ debug_asset_server = ["bevy_internal/debug_asset_server"] animation = ["bevy_internal/animation"] [dependencies] -bevy_dylib = { path = "crates/bevy_dylib", version = "0.7.0-dev", default-features = false, optional = true } -bevy_internal = { path = "crates/bevy_internal", version = "0.7.0-dev", default-features = false } +bevy_dylib = { path = "crates/bevy_dylib", version = "0.8.0-dev", default-features = false, optional = true } +bevy_internal = { path = "crates/bevy_internal", version = "0.8.0-dev", default-features = false } [target.'cfg(target_arch = "wasm32")'.dependencies] -bevy_internal = { path = "crates/bevy_internal", version = "0.7.0-dev", default-features = false, features = [ +bevy_internal = { path = "crates/bevy_internal", version = "0.8.0-dev", default-features = false, features = [ "webgl", ] } @@ -127,14 +127,6 @@ name = "hello_world" path = "examples/hello_world.rs" # 2D Rendering -[[example]] -name = "contributors" -path = "examples/2d/contributors.rs" - -[[example]] -name = "many_sprites" -path = "examples/2d/many_sprites.rs" - [[example]] name = "move_sprite" path = "examples/2d/move_sprite.rs" @@ -188,10 +180,6 @@ path = "examples/3d/lighting.rs" name = "load_gltf" path = "examples/3d/load_gltf.rs" -[[example]] -name = "many_cubes" -path = "examples/3d/many_cubes.rs" - [[example]] name = "msaa" path = "examples/3d/msaa.rs" @@ -228,6 +216,10 @@ path = "examples/3d/texture.rs" name = "render_to_texture" path = "examples/3d/render_to_texture.rs" +[[example]] +name = "two_passes" +path = "examples/3d/two_passes.rs" + [[example]] name = "update_gltf_scene" path = "examples/3d/update_gltf_scene.rs" @@ -414,15 +406,19 @@ path = "examples/ecs/timers.rs" # Games [[example]] name = "alien_cake_addict" -path = "examples/game/alien_cake_addict.rs" +path = "examples/games/alien_cake_addict.rs" [[example]] name = "breakout" -path = "examples/game/breakout.rs" +path = "examples/games/breakout.rs" + +[[example]] +name = "contributors" +path = "examples/games/contributors.rs" [[example]] name = "game_menu" -path = "examples/game/game_menu.rs" +path = "examples/games/game_menu.rs" # Input [[example]] @@ -524,10 +520,29 @@ path = "examples/shader/animate_shader.rs" name = "compute_shader_game_of_life" path = "examples/shader/compute_shader_game_of_life.rs" -# Tools +# Stress tests + [[example]] name = "bevymark" -path = "examples/tools/bevymark.rs" +path = "examples/stress_tests/bevymark.rs" + +[[example]] +name = "many_cubes" +path = "examples/stress_tests/many_cubes.rs" + +[[example]] +name = "many_lights" +path = "examples/stress_tests/many_lights.rs" + +[[example]] +name = "many_sprites" +path = "examples/stress_tests/many_sprites.rs" + +[[example]] +name = "transform_hierarchy" +path = "examples/stress_tests/transform_hierarchy.rs" + +# Tools [[example]] name = "scene_viewer" @@ -614,12 +629,3 @@ icon = "@mipmap/ic_launcher" build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"] min_sdk_version = 16 target_sdk_version = 29 - -# Stress Tests -[[example]] -name = "many_lights" -path = "examples/stress_tests/many_lights.rs" - -[[example]] -name = "transform_hierarchy" -path = "examples/stress_tests/transform_hierarchy.rs" diff --git a/assets/sounds/breakout_collision.ogg b/assets/sounds/breakout_collision.ogg new file mode 100644 index 0000000000000..0211d70cfb845 Binary files /dev/null and b/assets/sounds/breakout_collision.ogg differ diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml index 223e90e61969f..fdb9bd164ce6b 100644 --- a/crates/bevy_animation/Cargo.toml +++ b/crates/bevy_animation/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_animation" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides animation functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,12 +10,12 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml index 1dc35210e4671..602dd466e798c 100644 --- a/crates/bevy_app/Cargo.toml +++ b/crates/bevy_app/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_app" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides core App functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -15,10 +15,10 @@ default = ["bevy_reflect"] [dependencies] # bevy -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", optional = true } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", optional = true } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } @@ -31,4 +31,4 @@ web-sys = { version = "0.3", features = [ "Window" ] } [dev-dependencies] # bevy -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 02f0e589eca3e..5ccf6ac63f5c9 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_asset" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides asset functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -15,13 +15,13 @@ debug_asset_server = ["filesystem_watcher"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_tasks = { path = "../bevy_tasks", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other serde = { version = "1", features = ["derive"] } @@ -45,4 +45,4 @@ ndk-glue = { version = "0.5" } [dev-dependencies] futures-lite = "1.4.0" tempfile = "3.2.0" -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } diff --git a/crates/bevy_audio/Cargo.toml b/crates/bevy_audio/Cargo.toml index dd26c94f2bd35..3e7603f82c700 100644 --- a/crates/bevy_audio/Cargo.toml +++ b/crates/bevy_audio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_audio" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides audio functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,11 +10,11 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other anyhow = "1.0.4" @@ -26,7 +26,7 @@ rodio = { version = "0.15", default-features = false, features = ["wasm-bindgen" [dev-dependencies] # bevy -bevy_internal = { path = "../bevy_internal", version = "0.7.0-dev" } +bevy_internal = { path = "../bevy_internal", version = "0.8.0-dev" } [features] mp3 = ["rodio/mp3"] diff --git a/crates/bevy_core/Cargo.toml b/crates/bevy_core/Cargo.toml index 74c02c3b44e06..4b3b7f336daa6 100644 --- a/crates/bevy_core/Cargo.toml +++ b/crates/bevy_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_core" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides core functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -11,13 +11,13 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev", features = ["bevy_reflect"] } -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev", features = ["bevy_reflect"] } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_tasks = { path = "../bevy_tasks", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev", features = ["bevy_reflect"] } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", features = ["bevy_reflect"] } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other bytemuck = "1.5" diff --git a/crates/bevy_core/src/time/time.rs b/crates/bevy_core/src/time/time.rs index c47855e974a74..dd75fc818d134 100644 --- a/crates/bevy_core/src/time/time.rs +++ b/crates/bevy_core/src/time/time.rs @@ -75,13 +75,13 @@ impl Time { self.startup } - /// The ['Instant'] when [`Time::update`] was last called, if it exists + /// The [`Instant`] when [`Time::update`] was last called, if it exists #[inline] pub fn last_update(&self) -> Option { self.last_update } - /// The ['Duration'] from startup to the last update + /// The [`Duration`] from startup to the last update #[inline] pub fn time_since_startup(&self) -> Duration { self.time_since_startup diff --git a/crates/bevy_core_pipeline/Cargo.toml b/crates/bevy_core_pipeline/Cargo.toml index 4b8b862820460..0fa33d8ec0e5a 100644 --- a/crates/bevy_core_pipeline/Cargo.toml +++ b/crates/bevy_core_pipeline/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_core_pipeline" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" authors = [ "Bevy Contributors ", @@ -17,10 +17,10 @@ trace = [] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } diff --git a/crates/bevy_core_pipeline/src/lib.rs b/crates/bevy_core_pipeline/src/lib.rs index 8fa6be9f299c2..e9d0c9b8b9db5 100644 --- a/crates/bevy_core_pipeline/src/lib.rs +++ b/crates/bevy_core_pipeline/src/lib.rs @@ -23,7 +23,7 @@ use bevy_app::{App, Plugin}; use bevy_core::FloatOrd; use bevy_ecs::prelude::*; use bevy_render::{ - camera::{ActiveCamera, Camera2d, Camera3d, RenderTarget}, + camera::{ActiveCamera, Camera2d, Camera3d, ExtractedCamera, RenderTarget}, color::Color, render_graph::{EmptyNode, RenderGraph, SlotInfo, SlotType}, render_phase::{ @@ -390,7 +390,7 @@ pub fn prepare_core_views_system( msaa: Res, render_device: Res, views_3d: Query< - (Entity, &ExtractedView), + (Entity, &ExtractedView, Option<&ExtractedCamera>), ( With>, With>, @@ -398,24 +398,35 @@ pub fn prepare_core_views_system( ), >, ) { - for (entity, view) in views_3d.iter() { - let cached_texture = texture_cache.get( - &render_device, - TextureDescriptor { - label: Some("view_depth_texture"), - size: Extent3d { - depth_or_array_layers: 1, - width: view.width as u32, - height: view.height as u32, + let mut textures = HashMap::default(); + for (entity, view, camera) in views_3d.iter() { + let mut get_cached_texture = || { + texture_cache.get( + &render_device, + TextureDescriptor { + label: Some("view_depth_texture"), + size: Extent3d { + depth_or_array_layers: 1, + width: view.width as u32, + height: view.height as u32, + }, + mip_level_count: 1, + sample_count: msaa.samples, + dimension: TextureDimension::D2, + format: TextureFormat::Depth32Float, /* PERF: vulkan docs recommend using 24 + * bit depth for better performance */ + usage: TextureUsages::RENDER_ATTACHMENT, }, - mip_level_count: 1, - sample_count: msaa.samples, - dimension: TextureDimension::D2, - format: TextureFormat::Depth32Float, /* PERF: vulkan docs recommend using 24 - * bit depth for better performance */ - usage: TextureUsages::RENDER_ATTACHMENT, - }, - ); + ) + }; + let cached_texture = if let Some(camera) = camera { + textures + .entry(camera.target.clone()) + .or_insert_with(get_cached_texture) + .clone() + } else { + get_cached_texture() + }; commands.entity(entity).insert(ViewDepthTexture { texture: cached_texture.texture, view: cached_texture.default_view, diff --git a/crates/bevy_core_pipeline/src/main_pass_3d.rs b/crates/bevy_core_pipeline/src/main_pass_3d.rs index 242a0596be565..28841e8acbfd4 100644 --- a/crates/bevy_core_pipeline/src/main_pass_3d.rs +++ b/crates/bevy_core_pipeline/src/main_pass_3d.rs @@ -142,12 +142,15 @@ impl Node for MainPass3dNode { })], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { view: &depth.view, - // NOTE: For the transparent pass we load the depth buffer but do not write to it. + // NOTE: For the transparent pass we load the depth buffer. There should be no + // need to write to it, but store is set to `true` as a workaround for issue #3776, + // https://github.com/bevyengine/bevy/issues/3776 + // so that wgpu does not clear the depth buffer. // As the opaque and alpha mask passes run first, opaque meshes can occlude // transparent ones. depth_ops: Some(Operations { load: LoadOp::Load, - store: false, + store: true, }), stencil_ops: None, }), diff --git a/crates/bevy_core_pipeline/src/main_pass_driver.rs b/crates/bevy_core_pipeline/src/main_pass_driver.rs index f317b4d0bd16e..c4347ef14eab1 100644 --- a/crates/bevy_core_pipeline/src/main_pass_driver.rs +++ b/crates/bevy_core_pipeline/src/main_pass_driver.rs @@ -14,17 +14,17 @@ impl Node for MainPassDriverNode { _render_context: &mut RenderContext, world: &World, ) -> Result<(), NodeRunError> { - if let Some(camera_2d) = world.resource::>().get() { + if let Some(camera_3d) = world.resource::>().get() { graph.run_sub_graph( - crate::draw_2d_graph::NAME, - vec![SlotValue::Entity(camera_2d)], + crate::draw_3d_graph::NAME, + vec![SlotValue::Entity(camera_3d)], )?; } - if let Some(camera_3d) = world.resource::>().get() { + if let Some(camera_2d) = world.resource::>().get() { graph.run_sub_graph( - crate::draw_3d_graph::NAME, - vec![SlotValue::Entity(camera_3d)], + crate::draw_2d_graph::NAME, + vec![SlotValue::Entity(camera_2d)], )?; } diff --git a/crates/bevy_crevice/Cargo.toml b/crates/bevy_crevice/Cargo.toml index c3cb334f53b86..6ab98134a8440 100644 --- a/crates/bevy_crevice/Cargo.toml +++ b/crates/bevy_crevice/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bevy_crevice" description = "Create GLSL-compatible versions of structs with explicitly-initialized padding (Bevy version)" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" authors = ["Lucien Greathouse "] documentation = "https://docs.rs/crevice" @@ -23,7 +23,7 @@ std = [] # default-members = ["crevice-derive", "crevice-tests"] [dependencies] -bevy-crevice-derive = { version = "0.7.0-dev", path = "bevy-crevice-derive" } +bevy-crevice-derive = { version = "0.8.0-dev", path = "bevy-crevice-derive" } bytemuck = "1.4.1" mint = "0.5.8" diff --git a/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml b/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml index ae0d5db17dabf..cc0042ae38244 100644 --- a/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml +++ b/crates/bevy_crevice/bevy-crevice-derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bevy-crevice-derive" description = "Derive crate for the 'crevice' crate (Bevy version)" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2018" authors = ["Lucien Greathouse "] documentation = "https://docs.rs/crevice-derive" @@ -24,4 +24,4 @@ proc-macro = true syn = "1.0.40" quote = "1.0.7" proc-macro2 = "1.0.21" -bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.7.0-dev" } +bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" } diff --git a/crates/bevy_derive/Cargo.toml b/crates/bevy_derive/Cargo.toml index a269eb437456b..0e9a101bb482d 100644 --- a/crates/bevy_derive/Cargo.toml +++ b/crates/bevy_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_derive" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides derive implementations for Bevy Engine" homepage = "https://bevyengine.org" @@ -12,7 +12,7 @@ keywords = ["bevy"] proc-macro = true [dependencies] -bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.7.0-dev" } +bevy_macro_utils = { path = "../bevy_macro_utils", version = "0.8.0-dev" } quote = "1.0" syn = "1.0" diff --git a/crates/bevy_diagnostic/Cargo.toml b/crates/bevy_diagnostic/Cargo.toml index fd07f4e273d6c..de94e29af557b 100644 --- a/crates/bevy_diagnostic/Cargo.toml +++ b/crates/bevy_diagnostic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_diagnostic" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides diagnostic functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -11,8 +11,8 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } diff --git a/crates/bevy_dylib/Cargo.toml b/crates/bevy_dylib/Cargo.toml index 173da74f67f91..a845c44ada155 100644 --- a/crates/bevy_dylib/Cargo.toml +++ b/crates/bevy_dylib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_dylib" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Force the Bevy Engine to be dynamically linked for faster linking" homepage = "https://bevyengine.org" @@ -12,4 +12,4 @@ keywords = ["bevy"] crate-type = ["dylib"] [dependencies] -bevy_internal = { path = "../bevy_internal", version = "0.7.0-dev", default-features = false } +bevy_internal = { path = "../bevy_internal", version = "0.8.0-dev", default-features = false } diff --git a/crates/bevy_dynamic_plugin/Cargo.toml b/crates/bevy_dynamic_plugin/Cargo.toml index 9a3bf48b35eea..169738069c7b0 100644 --- a/crates/bevy_dynamic_plugin/Cargo.toml +++ b/crates/bevy_dynamic_plugin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_dynamic_plugin" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides dynamic plugin loading capabilities for non-wasm platforms" homepage = "https://bevyengine.org" @@ -12,7 +12,7 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } # other libloading = { version = "0.7" } diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 93f5fc1e5d76b..d64e0f4830c1b 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_ecs" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Bevy Engine's entity component system" homepage = "https://bevyengine.org" @@ -14,10 +14,10 @@ trace = [] default = ["bevy_reflect"] [dependencies] -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", optional = true } -bevy_tasks = { path = "../bevy_tasks", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } -bevy_ecs_macros = { path = "macros", version = "0.7.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", optional = true } +bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_ecs_macros = { path = "macros", version = "0.8.0-dev" } async-channel = "1.4" fixedbitset = "0.4" diff --git a/crates/bevy_ecs/macros/Cargo.toml b/crates/bevy_ecs/macros/Cargo.toml index d864138723c7d..0773347f61b1b 100644 --- a/crates/bevy_ecs/macros/Cargo.toml +++ b/crates/bevy_ecs/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_ecs_macros" -version = "0.7.0-dev" +version = "0.8.0-dev" description = "Bevy ECS Macros" edition = "2021" license = "MIT OR Apache-2.0" @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" proc-macro = true [dependencies] -bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.7.0-dev" } +bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" } syn = "1.0" quote = "1.0" diff --git a/crates/bevy_ecs/macros/src/fetch.rs b/crates/bevy_ecs/macros/src/fetch.rs index ddeb301c19974..796a5b546b423 100644 --- a/crates/bevy_ecs/macros/src/fetch.rs +++ b/crates/bevy_ecs/macros/src/fetch.rs @@ -28,6 +28,8 @@ mod field_attr_keywords { pub static WORLD_QUERY_ATTRIBUTE_NAME: &str = "world_query"; pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream { + let visibility = ast.vis; + let mut fetch_struct_attributes = FetchStructAttributes::default(); for attr in &ast.attrs { if !attr @@ -233,7 +235,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream { item_struct_name: Ident| { if is_filter { quote! { - struct #fetch_struct_name #impl_generics #where_clause { + #[doc(hidden)] + #visibility struct #fetch_struct_name #impl_generics #where_clause { #(#field_idents: <#field_types as #path::query::WorldQuery>::#fetch_associated_type,)* #(#ignored_field_idents: #ignored_field_types,)* } @@ -277,12 +280,13 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream { } else { quote! { #derive_macro_call - struct #item_struct_name #impl_generics #where_clause { + #visibility struct #item_struct_name #impl_generics #where_clause { #(#(#field_attrs)* #field_visibilities #field_idents: <<#field_types as #path::query::WorldQuery>::#fetch_associated_type as #path::query::Fetch<#world_lifetime, #world_lifetime>>::Item,)* #(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)* } - struct #fetch_struct_name #impl_generics #where_clause { + #[doc(hidden)] + #visibility struct #fetch_struct_name #impl_generics #where_clause { #(#field_idents: <#field_types as #path::query::WorldQuery>::#fetch_associated_type,)* #(#ignored_field_idents: #ignored_field_types,)* } @@ -342,7 +346,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream { ); let state_impl = quote! { - struct #state_struct_name #impl_generics #where_clause { + #[doc(hidden)] + #visibility struct #state_struct_name #impl_generics #where_clause { #(#field_idents: <#field_types as #path::query::WorldQuery>::State,)* #(#ignored_field_idents: #ignored_field_types,)* } diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 7d3f541dab930..d9495f80c48d1 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -17,13 +17,19 @@ pub trait Command: Send + Sync + 'static { fn write(self, world: &mut World); } -/// A list of commands that modify a [`World`], running at the end of the stage where they -/// have been invoked. +/// A list of commands that runs at the end of the stage of the system that called them. +/// +/// Commands are executed one at a time in an exclusive fashion. +//// Each command can be used to modify the [`World`] in arbitrary ways: +/// * spawning or despawning entities +/// * inserting components on new or existing entities +/// * inserting resources +/// * etc. /// /// # Usage /// -/// `Commands` is a [`SystemParam`](crate::system::SystemParam), therefore it is declared -/// as a function parameter: +/// Add `mut commands: Commands` as a function argument to your system to get a copy of this struct that will be applied at the end of the current stage. +/// Commands are almost always used as a [`SystemParam`](crate::system::SystemParam). /// /// ``` /// # use bevy_ecs::prelude::*; @@ -33,7 +39,8 @@ pub trait Command: Send + Sync + 'static { /// } /// ``` /// -/// Then, commands can be invoked by calling the methods of `commands`. +/// Each command is implemented as a separate method. +/// Check the [`Command`] trait for a list of available commands (or implement your own!). pub struct Commands<'w, 's> { queue: &'s mut CommandQueue, entities: &'w Entities, @@ -284,10 +291,10 @@ impl<'w, 's> Commands<'w, 's> { /// # high_score: u32, /// # } /// # - /// # fn system(mut commands: Commands) { + /// # fn initialise_scoreboard(mut commands: Commands) { /// commands.init_resource::(); /// # } - /// # system.system(); + /// # bevy_ecs::system::assert_is_system(initialise_scoreboard); /// ``` pub fn init_resource(&mut self) { self.queue.push(InitResource:: { diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 30f421cabad37..87243af604171 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -249,7 +249,7 @@ impl FromWorld for SystemState { /// /// fn my_system_function(an_usize_resource: Res) {} /// -/// let system = IntoSystem::system(my_system_function); +/// let system = IntoSystem::into_system(my_system_function); /// ``` // This trait has to be generic because we have potentially overlapping impls, in particular // because Rust thinks a type could impl multiple different `FnMut` combinations @@ -257,26 +257,6 @@ impl FromWorld for SystemState { pub trait IntoSystem: Sized { type System: System; /// Turns this value into its corresponding [`System`]. - /// - /// Use of this method was formerly required whenever adding a `system` to an `App`. - /// or other cases where a system is required. - /// However, since [#2398](https://github.com/bevyengine/bevy/pull/2398), - /// this is no longer required. - /// - /// In future, this method will be removed. - /// - /// One use of this method is to assert that a given function is a valid system. - /// For this case, use [`bevy_ecs::system::assert_is_system`] instead. - /// - /// [`bevy_ecs::system::assert_is_system`]: [`crate::system::assert_is_system`]: - #[deprecated( - since = "0.7.0", - note = "`.system()` is no longer needed, as methods which accept systems will convert functions into a system automatically" - )] - fn system(self) -> Self::System { - IntoSystem::into_system(self) - } - /// Turns this value into its corresponding [`System`]. fn into_system(this: Self) -> Self::System; } @@ -322,7 +302,7 @@ pub struct InputMarker; /// The [`System`] counter part of an ordinary function. /// -/// You get this by calling [`IntoSystem::system`] on a function that only accepts +/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts /// [`SystemParam`]s. The output of the system becomes the functions return type, while the input /// becomes the functions [`In`] tagged parameter or `()` if no such parameter exists. pub struct FunctionSystem diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index eb5a3d34106d1..304fd5c4035dc 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -625,7 +625,7 @@ where /// /// Note that the unlike [`Query::get_many_mut`], the entities passed in do not need to be unique. /// - /// See [`Query::multiple`] for the infallible equivalent. + /// See [`Query::many`] for the infallible equivalent. #[inline] pub fn get_many( &self, @@ -669,7 +669,7 @@ where /// fn check_all_targets_in_range(targeting_query: Query<(Entity, &Targets, &Position)>, targets_query: Query<&Position>){ /// for (targeting_entity, targets, origin) in targeting_query.iter(){ /// // We can use "destructuring" to unpack the results nicely - /// let [target_1, target_2, target_3] = targets_query.multiple(targets.0); + /// let [target_1, target_2, target_3] = targets_query.many(targets.0); /// /// assert!(target_1.distance(origin) <= 5); /// assert!(target_2.distance(origin) <= 5); @@ -678,7 +678,7 @@ where /// } /// ``` #[inline] - pub fn multiple( + pub fn many( &self, entities: [Entity; N], ) -> [>::Item; N] { @@ -731,7 +731,7 @@ where /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is /// returned instead. /// - /// See [`Query::multiple_mut`] for the infallible equivalent. + /// See [`Query::many_mut`] for the infallible equivalent. #[inline] pub fn get_many_mut( &mut self, @@ -778,7 +778,7 @@ where /// fn spring_forces(spring_query: Query<&Spring>, mut mass_query: Query<(&Position, &mut Force)>){ /// for spring in spring_query.iter(){ /// // We can use "destructuring" to unpack our query items nicely - /// let [(position_1, mut force_1), (position_2, mut force_2)] = mass_query.multiple_mut(spring.connected_entities); + /// let [(position_1, mut force_1), (position_2, mut force_2)] = mass_query.many_mut(spring.connected_entities); /// /// force_1.x += spring.strength * (position_1.x - position_2.x); /// force_1.y += spring.strength * (position_1.y - position_2.y); @@ -790,7 +790,7 @@ where /// } /// ``` #[inline] - pub fn multiple_mut( + pub fn many_mut( &mut self, entities: [Entity; N], ) -> [>::Item; N] { @@ -1138,7 +1138,7 @@ where /// println!("Bam!") /// } /// } - /// # targeting_system.system(); + /// # bevy_ecs::system::assert_is_system(targeting_system); /// ``` #[inline] pub fn contains(&self, entity: Entity) -> bool { diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index f47e88e9b8bfd..24c7db76f15a7 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -17,13 +17,13 @@ use crate::{ storage::{Column, SparseSet, Storages}, system::Resource, }; +use bevy_utils::tracing::debug; use std::{ any::TypeId, fmt, mem::ManuallyDrop, sync::atomic::{AtomicU32, Ordering}, }; - mod identifier; pub use identifier::WorldId; @@ -463,6 +463,7 @@ impl World { /// ``` #[inline] pub fn despawn(&mut self, entity: Entity) -> bool { + debug!("Despawning entity {:?}", entity); self.get_entity_mut(entity) .map(|e| { e.despawn(); diff --git a/crates/bevy_ecs_compile_fail_tests/Cargo.toml b/crates/bevy_ecs_compile_fail_tests/Cargo.toml index 4c555764798a1..7fa3316d360ae 100644 --- a/crates/bevy_ecs_compile_fail_tests/Cargo.toml +++ b/crates/bevy_ecs_compile_fail_tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_ecs_compile_fail_tests" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Compile fail tests for Bevy Engine's entity component system" homepage = "https://bevyengine.org" @@ -9,5 +9,5 @@ license = "MIT OR Apache-2.0" publish = false [dev-dependencies] -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } trybuild = "1.0" diff --git a/crates/bevy_gilrs/Cargo.toml b/crates/bevy_gilrs/Cargo.toml index 9516c96f4cd9a..f67ce8794cfdb 100644 --- a/crates/bevy_gilrs/Cargo.toml +++ b/crates/bevy_gilrs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gilrs" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Gamepad system made using Gilrs for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,10 +10,10 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_input = { path = "../bevy_input", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other gilrs = { version = "0.8.0", features = ["wasm-bindgen"] } diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index 13c0da7038928..c2cb4bcf6dfd0 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gltf" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Bevy Engine GLTF loading" homepage = "https://bevyengine.org" @@ -10,20 +10,20 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_animation = { path = "../bevy_animation", version = "0.7.0-dev", optional = true } -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_pbr = { path = "../bevy_pbr", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_scene = { path = "../bevy_scene", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_animation = { path = "../bevy_animation", version = "0.8.0-dev", optional = true } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_pbr = { path = "../bevy_pbr", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_scene = { path = "../bevy_scene", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other gltf = { version = "1.0.0", default-features = false, features = [ diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml index 5041512d61296..f7cb27f106a86 100644 --- a/crates/bevy_hierarchy/Cargo.toml +++ b/crates/bevy_hierarchy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_hierarchy" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides hierarchy functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -8,12 +8,15 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] +[features] +trace = [] + [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev", features = ["bevy_reflect"] } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", features = ["bevy_reflect"] } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } diff --git a/crates/bevy_hierarchy/src/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs index 56c9b0f8ad938..4d6753e719089 100644 --- a/crates/bevy_hierarchy/src/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -9,13 +9,15 @@ use bevy_utils::tracing::debug; /// Despawns the given entity and all its children recursively #[derive(Debug)] pub struct DespawnRecursive { - entity: Entity, + /// Target entity + pub entity: Entity, } /// Despawns the given entity's children recursively #[derive(Debug)] pub struct DespawnChildrenRecursive { - entity: Entity, + /// Target entity + pub entity: Entity, } /// Function for despawning an entity and all its children @@ -54,12 +56,26 @@ fn despawn_children(world: &mut World, entity: Entity) { impl Command for DespawnRecursive { fn write(self, world: &mut World) { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "command", + name = "DespawnRecursive", + entity = bevy_utils::tracing::field::debug(self.entity) + ) + .entered(); despawn_with_children_recursive(world, self.entity); } } impl Command for DespawnChildrenRecursive { fn write(self, world: &mut World) { + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "command", + name = "DespawnChildrenRecursive", + entity = bevy_utils::tracing::field::debug(self.entity) + ) + .entered(); despawn_children(world, self.entity); } } @@ -90,6 +106,14 @@ impl<'w> DespawnRecursiveExt for EntityMut<'w> { /// Despawns the provided entity and its children. fn despawn_recursive(mut self) { let entity = self.id(); + + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "despawn_recursive", + entity = bevy_utils::tracing::field::debug(entity) + ) + .entered(); + // SAFE: EntityMut is consumed so even though the location is no longer // valid, it cannot be accessed again with the invalid location. unsafe { @@ -99,6 +123,14 @@ impl<'w> DespawnRecursiveExt for EntityMut<'w> { fn despawn_descendants(&mut self) { let entity = self.id(); + + #[cfg(feature = "trace")] + let _span = bevy_utils::tracing::info_span!( + "despawn_descendants", + entity = bevy_utils::tracing::field::debug(entity) + ) + .entered(); + // SAFE: The location is updated. unsafe { despawn_children(self.world_mut(), entity); diff --git a/crates/bevy_input/Cargo.toml b/crates/bevy_input/Cargo.toml index f50f9093a87f2..17db1fd140301 100644 --- a/crates/bevy_input/Cargo.toml +++ b/crates/bevy_input/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_input" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides input functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -14,10 +14,10 @@ serialize = ["serde"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other serde = { version = "1", features = ["derive"], optional = true } diff --git a/crates/bevy_input/src/axis.rs b/crates/bevy_input/src/axis.rs index 842527b015c22..5820b5558b52e 100644 --- a/crates/bevy_input/src/axis.rs +++ b/crates/bevy_input/src/axis.rs @@ -1,12 +1,12 @@ use bevy_utils::HashMap; use std::hash::Hash; -/// Stores the position data of input devices of type T +/// Stores the position data of the input devices of type `T`. /// -/// Values are stored as `f32` values, which range from `min` to `max`. -/// The valid range is from -1.0 to 1.0, inclusive. +/// The values are stored as `f32`s, which range from [`Axis::MIN`] to [`Axis::MAX`], inclusive. #[derive(Debug)] pub struct Axis { + /// The position data of the input devices. axis_data: HashMap, } @@ -25,27 +25,29 @@ impl Axis where T: Copy + Eq + Hash, { + /// The smallest possible axis value. pub const MIN: f32 = -1.0; + + /// The largest possible axis value. pub const MAX: f32 = 1.0; - /// Inserts a position data for an input device, - /// restricting the position data to an interval `min..=max`. + /// Sets the position data of the `input_device` to `position_data`. /// - /// If the input device wasn't present before, [None] is returned. + /// The `position_data` is clamped to be between [`Axis::MIN`] and [`Axis::MAX`], inclusive. /// - /// If the input device was present, the position data is updated, and the old value is returned. + /// If the `input_device`: + /// - was present before, the position data is updated, and the old value is returned. + /// - wasn't present before, [None] is returned. pub fn set(&mut self, input_device: T, position_data: f32) -> Option { let new_position_data = position_data.clamp(Self::MIN, Self::MAX); self.axis_data.insert(input_device, new_position_data) } - /// Returns a position data corresponding to the input device. + /// Returns a position data corresponding to the `input_device`. pub fn get(&self, input_device: T) -> Option { self.axis_data.get(&input_device).copied() } - - /// Removes the position data of the input device, - /// returning the position data if the input device was previously set. + /// Removes the position data of the `input_device`, returning the position data if the input device was previously set. pub fn remove(&mut self, input_device: T) -> Option { self.axis_data.remove(&input_device) } diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index b7da9ced53a29..4ba55c0118967 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -3,38 +3,45 @@ use bevy_ecs::system::ResMut; use bevy_math::Vec2; use bevy_utils::HashMap; -/// Represents a touch event +/// A touch input event. /// -/// Every time the user touches the screen, a new `Start` event with an unique -/// identifier for the finger is generated. When the finger is lifted, an `End` +/// ## Logic +/// +/// Every time the user touches the screen, a new [`TouchPhase::Started`] event with an unique +/// identifier for the finger is generated. When the finger is lifted, the [`TouchPhase::Ended`] /// event is generated with the same finger id. /// -/// After a `Start` event has been emitted, there may be zero or more `Move` +/// After a [`TouchPhase::Started`] event has been emitted, there may be zero or more [`TouchPhase::Moved`] /// events when the finger is moved or the touch pressure changes. /// -/// The finger id may be reused by the system after an `End` event. The user -/// should assume that a new `Start` event received with the same id has nothing +/// The finger id may be reused by the system after an [`TouchPhase::Ended`] event. The user +/// should assume that a new [`TouchPhase::Started`] event received with the same id has nothing /// to do with the old finger and is a new finger. /// -/// A `Cancelled` event is emitted when the system has canceled tracking this +/// A [`TouchPhase::Cancelled`] event is emitted when the system has canceled tracking this /// touch, such as when the window loses focus, or on iOS if the user moves the /// device against their face. +/// +/// ## Note +/// +/// This event is the translated version of the `WindowEvent::Touch` from the `winit` crate. +/// It is available to the end user and can be used for game logic. #[derive(Debug, Clone, Copy, PartialEq)] pub struct TouchInput { + /// The phase of the touch input. pub phase: TouchPhase, + /// The position of the finger on the touchscreen. pub position: Vec2, - /// Describes how hard the screen was pressed. May be `None` if the platform - /// does not support pressure sensitivity. + /// Describes how hard the screen was pressed. /// - /// ## Platform-specific - /// - /// - Only available on **iOS** 9.0+ and **Windows** 8+. + /// May be [`None`] if the platform does not support pressure sensitivity. + /// This feature is only available on **iOS** 9.0+ and **Windows** 8+. pub force: Option, - /// Unique identifier of a finger. + /// The unique identifier of the finger. pub id: u64, } -/// Describes the force of a touch event +/// A force description of a [`Touch`](crate::touch::Touch) input. #[derive(Debug, Clone, Copy, PartialEq)] pub enum ForceTouch { /// On iOS, the force is calibrated so that the same number corresponds to @@ -63,65 +70,107 @@ pub enum ForceTouch { /// If the platform reports the force as normalized, we have no way of /// knowing how much pressure 1.0 corresponds to – we know it's the maximum /// amount of force, but as to how much force, you might either have to - /// press really really hard, or not hard at all, depending on the device. + /// press really hard, or not hard at all, depending on the device. Normalized(f64), } -/// Describes touch-screen input state. +/// A phase of a [`TouchInput`](crate::touch::TouchInput). +/// +/// ## Usage +/// +/// It is used to describe the phase of the touch input that is currently active. +/// This includes a phase that indicates that a touch input has started or ended, +/// or that a finger has moved. There is also a cancelled phase that indicates that +/// the system cancelled the tracking of the finger. #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub enum TouchPhase { + /// A finger started to touch the touchscreen. Started, + /// A finger moved over the touchscreen. Moved, + /// A finger stopped touching the touchscreen. Ended, + /// The system cancelled the tracking of the finger. + /// + /// This occurs when the window loses focus, or on iOS if the user moves the + /// device against their face. Cancelled, } +/// A touch input. +/// +/// ## Usage +/// +/// It is used to store the position and force of a touch input and also the `id` of the finger. +/// The data of the touch input comes from the [`TouchInput`] event and is being stored +/// inside of the [`Touches`] `bevy` resource. #[derive(Debug, Clone, Copy)] pub struct Touch { + /// The id of the touch input. id: u64, + /// The starting position of the touch input. start_position: Vec2, + /// The starting force of the touch input. start_force: Option, + /// The previous position of the touch input. previous_position: Vec2, + /// The previous force of the touch input. previous_force: Option, + /// The current position of the touch input. position: Vec2, + /// The current force of the touch input. force: Option, } impl Touch { + /// The delta of the current `position` and the `previous_position`. pub fn delta(&self) -> Vec2 { self.position - self.previous_position } + /// The distance of the `start_position` and the current `position`. pub fn distance(&self) -> Vec2 { self.position - self.start_position } + /// Returns the `id` of the touch. #[inline] pub fn id(&self) -> u64 { self.id } + /// Returns the `start_position` of the touch. #[inline] pub fn start_position(&self) -> Vec2 { self.start_position } + /// Returns the `start_force` of the touch. #[inline] pub fn start_force(&self) -> Option { self.start_force } + /// Returns the `previous_position` of the touch. #[inline] pub fn previous_position(&self) -> Vec2 { self.previous_position } + /// Returns the `previous_force` of the touch. + #[inline] + pub fn previous_force(&self) -> Option { + self.previous_force + } + + /// Returns the current `position` of the touch. #[inline] pub fn position(&self) -> Vec2 { self.position } + /// Returns the current `force` of the touch. #[inline] pub fn force(&self) -> Option { self.force @@ -142,51 +191,76 @@ impl From<&TouchInput> for Touch { } } +/// A collection of [`Touch`]es. +/// +/// ## Usage +/// +/// It is used to create a `bevy` resource that stores the data of the touches on a touchscreen +/// and can be accessed inside of a system. +/// +/// ## Updating +/// +/// The resource is updated inside of the [`touch_screen_input_system`](crate::touch::touch_screen_input_system). #[derive(Debug, Clone, Default)] pub struct Touches { + /// A collection of every [`Touch`] that is currently being pressed. pressed: HashMap, + /// A collection of every [`Touch`] that just got pressed. just_pressed: HashMap, + /// A collection of every [`Touch`] that just got released. just_released: HashMap, + /// A collection of every [`Touch`] that just got cancelled. just_cancelled: HashMap, } impl Touches { + /// An iterator visiting every pressed [`Touch`] input in arbitrary order. pub fn iter(&self) -> impl Iterator + '_ { self.pressed.values() } + /// Returns the [`Touch`] input corresponding to the `id` if it is being pressed. pub fn get_pressed(&self, id: u64) -> Option<&Touch> { self.pressed.get(&id) } + /// Returns `true` if the input corresponding to the `id` has just been pressed. pub fn just_pressed(&self, id: u64) -> bool { self.just_pressed.contains_key(&id) } + /// An iterator visiting every just pressed [`Touch`] input in arbitrary order. pub fn iter_just_pressed(&self) -> impl Iterator { self.just_pressed.values() } + /// Returns the [`Touch`] input corresponding to the `id` if it has just been released. pub fn get_released(&self, id: u64) -> Option<&Touch> { self.just_released.get(&id) } + /// Returns `true` if the input corresponding to the `id` has just been released. pub fn just_released(&self, id: u64) -> bool { self.just_released.contains_key(&id) } + /// An iterator visiting every just released [`Touch`] input in arbitrary order. pub fn iter_just_released(&self) -> impl Iterator { self.just_released.values() } + /// Returns `true` if the input corresponding to the `id` has just been cancelled. pub fn just_cancelled(&self, id: u64) -> bool { self.just_cancelled.contains_key(&id) } + /// An iterator visiting every just cancelled [`Touch`] input in arbitrary order. pub fn iter_just_cancelled(&self) -> impl Iterator { self.just_cancelled.values() } + /// Processes a [`TouchInput`] event by updating the `pressed`, `just_pressed`, + /// `just_released`, and `just_cancelled` collections. fn process_touch_event(&mut self, event: &TouchInput) { match event.phase { TouchPhase::Started => { @@ -213,6 +287,13 @@ impl Touches { }; } + /// Clears the `just_pressed`, `just_released`, and `just_cancelled` collections. + /// + /// This is not clearing the `pressed` collection, because it could incorrectly mark + /// a touch input as not pressed eventhough it is pressed. This could happen if the + /// touch input is not moving for a single frame and would therefore be marked as + /// not pressed, because this function is called on every single frame no matter + /// if there was an event or not. fn update(&mut self) { self.just_pressed.clear(); self.just_released.clear(); @@ -220,7 +301,12 @@ impl Touches { } } -/// Updates the `Touches` resource with the latest `TouchInput` events +/// Updates the [`Touches`] resource with the latest [`TouchInput`] events. +/// +/// ## Differences +/// +/// The main difference between the [`TouchInput`] event and the [`Touches`] resource is that +/// the latter has convenient functions like [`Touches::just_pressed`] and [`Touches::just_released`]. pub fn touch_screen_input_system( mut touch_state: ResMut, mut touch_input_events: EventReader, diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index c2a560fec1371..360c957e984bc 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_internal" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "An internal Bevy crate used to facilitate optional dynamic linking via the 'dynamic' feature" homepage = "https://bevyengine.org" @@ -10,7 +10,14 @@ keywords = ["game", "engine", "gamedev", "graphics", "bevy"] categories = ["game-engines", "graphics", "gui", "rendering"] [features] -trace = [ "bevy_app/trace", "bevy_ecs/trace", "bevy_log/trace", "bevy_render/trace", "bevy_core_pipeline/trace" ] +trace = [ + "bevy_app/trace", + "bevy_core_pipeline/trace", + "bevy_ecs/trace", + "bevy_log/trace", + "bevy_render/trace", + "bevy_hierarchy/trace" +] trace_chrome = [ "bevy_log/tracing-chrome" ] trace_tracy = ["bevy_render/tracing-tracy", "bevy_log/tracing-tracy" ] wgpu_trace = ["bevy_render/wgpu_trace"] @@ -58,35 +65,35 @@ animation = ["bevy_animation", "bevy_gltf/bevy_animation"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } -bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev" } -bevy_input = { path = "../bevy_input", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_scene = { path = "../bevy_scene", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } -bevy_tasks = { path = "../bevy_tasks", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } +bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } +bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_scene = { path = "../bevy_scene", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } +bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } # bevy (optional) -bevy_animation = { path = "../bevy_animation", optional = true, version = "0.7.0-dev" } -bevy_audio = { path = "../bevy_audio", optional = true, version = "0.7.0-dev" } -bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.7.0-dev" } -bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.7.0-dev" } -bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.7.0-dev" } -bevy_render = { path = "../bevy_render", optional = true, version = "0.7.0-dev" } -bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.7.0-dev" } -bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.7.0-dev" } -bevy_text = { path = "../bevy_text", optional = true, version = "0.7.0-dev" } -bevy_ui = { path = "../bevy_ui", optional = true, version = "0.7.0-dev" } -bevy_winit = { path = "../bevy_winit", optional = true, version = "0.7.0-dev" } -bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.7.0-dev" } +bevy_animation = { path = "../bevy_animation", optional = true, version = "0.8.0-dev" } +bevy_audio = { path = "../bevy_audio", optional = true, version = "0.8.0-dev" } +bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.8.0-dev" } +bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.8.0-dev" } +bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.8.0-dev" } +bevy_render = { path = "../bevy_render", optional = true, version = "0.8.0-dev" } +bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.8.0-dev" } +bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.8.0-dev" } +bevy_text = { path = "../bevy_text", optional = true, version = "0.8.0-dev" } +bevy_ui = { path = "../bevy_ui", optional = true, version = "0.8.0-dev" } +bevy_winit = { path = "../bevy_winit", optional = true, version = "0.8.0-dev" } +bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.8.0-dev" } [target.'cfg(target_os = "android")'.dependencies] ndk-glue = {version = "0.5", features = ["logger"]} diff --git a/crates/bevy_log/Cargo.toml b/crates/bevy_log/Cargo.toml index a149e98afe0b4..163a07a196458 100644 --- a/crates/bevy_log/Cargo.toml +++ b/crates/bevy_log/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_log" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides logging for Bevy Engine" homepage = "https://bevyengine.org" @@ -12,8 +12,8 @@ keywords = ["bevy"] trace = [ "tracing-error" ] [dependencies] -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } tracing-subscriber = {version = "0.3.1", features = ["registry", "env-filter"]} tracing-chrome = { version = "0.4.0", optional = true } @@ -29,4 +29,4 @@ console_error_panic_hook = "0.1.6" tracing-wasm = "0.2.1" [dev-dependencies] -bevy_internal = { path = "../bevy_internal", version = "0.7.0-dev" } +bevy_internal = { path = "../bevy_internal", version = "0.8.0-dev" } diff --git a/crates/bevy_macro_utils/Cargo.toml b/crates/bevy_macro_utils/Cargo.toml index 8530069276c78..5372bab50b8b8 100644 --- a/crates/bevy_macro_utils/Cargo.toml +++ b/crates/bevy_macro_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_macro_utils" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "A collection of utils for Bevy Engine" homepage = "https://bevyengine.org" diff --git a/crates/bevy_math/Cargo.toml b/crates/bevy_math/Cargo.toml index 47d3725041c0e..64c6e1e7879fb 100644 --- a/crates/bevy_math/Cargo.toml +++ b/crates/bevy_math/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_math" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides math functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,4 +10,4 @@ keywords = ["bevy"] [dependencies] glam = { version = "0.20.0", features = ["serde", "bytemuck"] } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } diff --git a/crates/bevy_mikktspace/Cargo.toml b/crates/bevy_mikktspace/Cargo.toml index 1b87a580da48b..758d88e3e6e28 100644 --- a/crates/bevy_mikktspace/Cargo.toml +++ b/crates/bevy_mikktspace/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_mikktspace" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" authors = ["Benjamin Wasty ", "David Harvey-Macaulay ", "Layl Bongers "] description = "Mikkelsen tangent space algorithm" diff --git a/crates/bevy_mikktspace/README.md b/crates/bevy_mikktspace/README.md index 1fbab2afd634c..5fabe817e1900 100644 --- a/crates/bevy_mikktspace/README.md +++ b/crates/bevy_mikktspace/README.md @@ -23,10 +23,10 @@ cargo run --example generate Licensed under either of - * Apache License, Version 2.0 - ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license - ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +* Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)) +* MIT license + ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT)) at your option. diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 04f01ab963f6e..9e9286183db39 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_pbr" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Adds PBR rendering to Bevy Engine" homepage = "https://bevyengine.org" @@ -13,17 +13,17 @@ webgl = [] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } # other bitflags = "1.2" diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 69eddb985944e..095d112cecff4 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -8,7 +8,7 @@ use bevy_render::{ camera::{Camera, CameraProjection, OrthographicProjection}, color::Color, prelude::Image, - primitives::{Aabb, CubemapFrusta, Frustum, Sphere}, + primitives::{Aabb, CubemapFrusta, Frustum, Plane, Sphere}, render_resource::BufferBindingType, renderer::RenderDevice, view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities}, @@ -366,7 +366,6 @@ pub struct Clusters { /// and explicitly-configured to avoid having unnecessarily many slices close to the camera. pub(crate) near: f32, pub(crate) far: f32, - aabbs: Vec, pub(crate) lights: Vec, } @@ -390,6 +389,13 @@ impl Clusters { // NOTE: Maximum 4096 clusters due to uniform buffer size constraints debug_assert!(self.dimensions.x * self.dimensions.y * self.dimensions.z <= 4096); } + fn clear(&mut self) { + self.tile_size = UVec2::ONE; + self.dimensions = UVec3::ZERO; + self.near = 0.0; + self.far = 0.0; + self.lights.clear(); + } } fn clip_to_view(inverse_projection: Mat4, clip: Vec4) -> Vec4 { @@ -397,98 +403,6 @@ fn clip_to_view(inverse_projection: Mat4, clip: Vec4) -> Vec4 { view / view.w } -fn screen_to_view(screen_size: Vec2, inverse_projection: Mat4, screen: Vec2, ndc_z: f32) -> Vec4 { - let tex_coord = screen / screen_size; - let clip = Vec4::new( - tex_coord.x * 2.0 - 1.0, - (1.0 - tex_coord.y) * 2.0 - 1.0, - ndc_z, - 1.0, - ); - clip_to_view(inverse_projection, clip) -} - -// Calculate the intersection of a ray from the eye through the view space position to a z plane -fn line_intersection_to_z_plane(origin: Vec3, p: Vec3, z: f32) -> Vec3 { - let v = p - origin; - let t = (z - Vec3::Z.dot(origin)) / Vec3::Z.dot(v); - origin + t * v -} - -#[allow(clippy::too_many_arguments)] -fn compute_aabb_for_cluster( - z_near: f32, - z_far: f32, - tile_size: Vec2, - screen_size: Vec2, - inverse_projection: Mat4, - is_orthographic: bool, - cluster_dimensions: UVec3, - ijk: UVec3, -) -> Aabb { - let ijk = ijk.as_vec3(); - - // Calculate the minimum and maximum points in screen space - let p_min = ijk.xy() * tile_size; - let p_max = p_min + tile_size; - - let cluster_min; - let cluster_max; - if is_orthographic { - // Use linear depth slicing for orthographic - - // Convert to view space at the cluster near and far planes - // NOTE: 1.0 is the near plane due to using reverse z projections - let p_min = screen_to_view( - screen_size, - inverse_projection, - p_min, - 1.0 - (ijk.z / cluster_dimensions.z as f32), - ) - .xyz(); - let p_max = screen_to_view( - screen_size, - inverse_projection, - p_max, - 1.0 - ((ijk.z + 1.0) / cluster_dimensions.z as f32), - ) - .xyz(); - - cluster_min = p_min.min(p_max); - cluster_max = p_min.max(p_max); - } else { - // Convert to view space at the near plane - // NOTE: 1.0 is the near plane due to using reverse z projections - let p_min = screen_to_view(screen_size, inverse_projection, p_min, 1.0); - let p_max = screen_to_view(screen_size, inverse_projection, p_max, 1.0); - - let z_far_over_z_near = -z_far / -z_near; - let cluster_near = if ijk.z == 0.0 { - 0.0 - } else { - -z_near * z_far_over_z_near.powf((ijk.z - 1.0) / (cluster_dimensions.z - 1) as f32) - }; - // NOTE: This could be simplified to: - // cluster_far = cluster_near * z_far_over_z_near; - let cluster_far = if cluster_dimensions.z == 1 { - -z_far - } else { - -z_near * z_far_over_z_near.powf(ijk.z / (cluster_dimensions.z - 1) as f32) - }; - - // Calculate the four intersection points of the min and max points with the cluster near and far planes - let p_min_near = line_intersection_to_z_plane(Vec3::ZERO, p_min.xyz(), cluster_near); - let p_min_far = line_intersection_to_z_plane(Vec3::ZERO, p_min.xyz(), cluster_far); - let p_max_near = line_intersection_to_z_plane(Vec3::ZERO, p_max.xyz(), cluster_near); - let p_max_far = line_intersection_to_z_plane(Vec3::ZERO, p_max.xyz(), cluster_far); - - cluster_min = p_min_near.min(p_min_far).min(p_max_near.min(p_max_far)); - cluster_max = p_min_near.max(p_min_far).max(p_max_near.max(p_max_far)); - } - - Aabb::from_min_max(cluster_min, cluster_max) -} - pub fn add_clusters( mut commands: Commands, cameras: Query<(Entity, Option<&ClusterConfig>), (With, Without)>, @@ -524,19 +438,42 @@ impl VisiblePointLights { } } +// NOTE: Keep in sync with bevy_pbr/src/render/pbr.wgsl fn view_z_to_z_slice( cluster_factors: Vec2, - z_slices: f32, + z_slices: u32, view_z: f32, is_orthographic: bool, ) -> u32 { - if is_orthographic { + let z_slice = if is_orthographic { // NOTE: view_z is correct in the orthographic case ((view_z - cluster_factors.x) * cluster_factors.y).floor() as u32 } else { // NOTE: had to use -view_z to make it positive else log(negative) is nan - ((-view_z).ln() * cluster_factors.x - cluster_factors.y + 1.0).clamp(0.0, z_slices - 1.0) - as u32 + ((-view_z).ln() * cluster_factors.x - cluster_factors.y + 1.0) as u32 + }; + // NOTE: We use min as we may limit the far z plane used for clustering to be closeer than + // the furthest thing being drawn. This means that we need to limit to the maximum cluster. + z_slice.min(z_slices - 1) +} + +// NOTE: Keep in sync as the inverse of view_z_to_z_slice above +fn z_slice_to_view_z( + near: f32, + far: f32, + z_slices: u32, + z_slice: u32, + is_orthographic: bool, +) -> f32 { + if is_orthographic { + return -near - (far - near) * z_slice as f32 / z_slices as f32; + } + + // Perspective + if z_slice == 0 { + 0.0 + } else { + -near * (far / near).powf((z_slice - 1) as f32 / (z_slices - 1) as f32) } } @@ -553,7 +490,7 @@ fn ndc_position_to_cluster( let xy = (frag_coord * cluster_dimensions_f32.xy()).floor(); let z_slice = view_z_to_z_slice( cluster_factors, - cluster_dimensions.z as f32, + cluster_dimensions.z, view_z, is_orthographic, ); @@ -712,8 +649,13 @@ pub(crate) fn assign_lights_to_clusters( lights_query: Query<(Entity, &GlobalTransform, &PointLight, &Visibility)>, mut lights: Local>, mut max_point_lights_warning_emitted: Local, - render_device: Res, + render_device: Option>, ) { + let render_device = match render_device { + Some(render_device) => render_device, + None => return, + }; + global_lights.entities.clear(); lights.clear(); // collect just the relevant light query data into a persisted vec to avoid reallocating each frame @@ -787,18 +729,24 @@ pub(crate) fn assign_lights_to_clusters( for (view_entity, camera_transform, camera, frustum, config, clusters, mut visible_lights) in views.iter_mut() { - if matches!(config, ClusterConfig::None) && visible_lights.is_some() { - commands.entity(view_entity).remove::(); + let clusters = clusters.into_inner(); + + if matches!(config, ClusterConfig::None) { + if visible_lights.is_some() { + commands.entity(view_entity).remove::(); + } + clusters.clear(); continue; } - let clusters = clusters.into_inner(); - let screen_size = camera.target.get_physical_size(&windows, &images); - - clusters.aabbs.clear(); - clusters.lights.clear(); + let screen_size = + if let Some(screen_size) = camera.target.get_physical_size(&windows, &images) { + screen_size + } else { + clusters.clear(); + continue; + }; - let screen_size = screen_size.unwrap_or_default(); let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size); let view_transform = camera_transform.compute_matrix(); @@ -819,8 +767,9 @@ pub(crate) fn assign_lights_to_clusters( } ClusterFarZMode::Constant(far) => far, }; - let first_slice_depth = match requested_cluster_dimensions.z { - 1 => config.first_slice_depth().max(far_z), + let first_slice_depth = match (is_orthographic, requested_cluster_dimensions.z) { + (true, _) => camera.near, + (false, 1) => config.first_slice_depth().max(far_z), _ => config.first_slice_depth(), }; // NOTE: Ensure the far_z is at least as far as the first_depth_slice to avoid clustering problems. @@ -857,13 +806,13 @@ pub(crate) fn assign_lights_to_clusters( // since we won't adjust z slices we can calculate exact number of slices required in z dimension let z_cluster_min = view_z_to_z_slice( cluster_factors, - requested_cluster_dimensions.z as f32, + requested_cluster_dimensions.z, light_aabb_min.z, is_orthographic, ); let z_cluster_max = view_z_to_z_slice( cluster_factors, - requested_cluster_dimensions.z as f32, + requested_cluster_dimensions.z, light_aabb_max.z, is_orthographic, ); @@ -919,52 +868,72 @@ pub(crate) fn assign_lights_to_clusters( let inverse_projection = camera.projection_matrix.inverse(); - let screen_size = screen_size.as_vec2(); - let tile_size_u32 = clusters.tile_size; - let tile_size = tile_size_u32.as_vec2(); - // Calculate view space AABBs - // NOTE: It is important that these are iterated in a specific order - // so that we can calculate the cluster index in the fragment shader! - // I (Rob Swain) choose to scan along rows of tiles in x,y, and for each tile then scan - // along z - for y in 0..clusters.dimensions.y { - for x in 0..clusters.dimensions.x { - for z in 0..clusters.dimensions.z { - clusters.aabbs.push(compute_aabb_for_cluster( - clusters.near, - clusters.far, - tile_size, - screen_size, - inverse_projection, - is_orthographic, - clusters.dimensions, - UVec3::new(x, y, z), - )); - } - } - } - for lights in clusters.lights.iter_mut() { lights.entities.clear(); } - clusters - .lights - .resize_with(clusters.aabbs.len(), VisiblePointLights::default); + clusters.lights.resize_with( + (clusters.dimensions.x * clusters.dimensions.y * clusters.dimensions.z) as usize, + VisiblePointLights::default, + ); - if screen_size.x == 0.0 || screen_size.y == 0.0 { - continue; + // Calculate the x/y/z cluster frustum planes in view space + let mut x_planes = Vec::with_capacity(clusters.dimensions.x as usize + 1); + let mut y_planes = Vec::with_capacity(clusters.dimensions.y as usize + 1); + let mut z_planes = Vec::with_capacity(clusters.dimensions.z as usize + 1); + + if is_orthographic { + let x_slices = clusters.dimensions.x as f32; + for x in 0..=clusters.dimensions.x { + let x_proportion = x as f32 / x_slices; + let x_pos = x_proportion * 2.0 - 1.0; + let view_x = clip_to_view(inverse_projection, Vec4::new(x_pos, 0.0, 1.0, 1.0)).x; + let normal = Vec3::X; + let d = view_x * normal.x; + x_planes.push(Plane::new(normal.extend(d))); + } + + let y_slices = clusters.dimensions.y as f32; + for y in 0..=clusters.dimensions.y { + let y_proportion = 1.0 - y as f32 / y_slices; + let y_pos = y_proportion * 2.0 - 1.0; + let view_y = clip_to_view(inverse_projection, Vec4::new(0.0, y_pos, 1.0, 1.0)).y; + let normal = Vec3::Y; + let d = view_y * normal.y; + y_planes.push(Plane::new(normal.extend(d))); + } + } else { + let x_slices = clusters.dimensions.x as f32; + for x in 0..=clusters.dimensions.x { + let x_proportion = x as f32 / x_slices; + let x_pos = x_proportion * 2.0 - 1.0; + let nb = clip_to_view(inverse_projection, Vec4::new(x_pos, -1.0, 1.0, 1.0)).xyz(); + let nt = clip_to_view(inverse_projection, Vec4::new(x_pos, 1.0, 1.0, 1.0)).xyz(); + let normal = nb.cross(nt); + let d = nb.dot(normal); + x_planes.push(Plane::new(normal.extend(d))); + } + + let y_slices = clusters.dimensions.y as f32; + for y in 0..=clusters.dimensions.y { + let y_proportion = 1.0 - y as f32 / y_slices; + let y_pos = y_proportion * 2.0 - 1.0; + let nl = clip_to_view(inverse_projection, Vec4::new(-1.0, y_pos, 1.0, 1.0)).xyz(); + let nr = clip_to_view(inverse_projection, Vec4::new(1.0, y_pos, 1.0, 1.0)).xyz(); + let normal = nr.cross(nl); + let d = nr.dot(normal); + y_planes.push(Plane::new(normal.extend(d))); + } } - let mut visible_lights_scratch = Vec::new(); + let z_slices = clusters.dimensions.z; + for z in 0..=z_slices { + let view_z = z_slice_to_view_z(first_slice_depth, far_z, z_slices, z, is_orthographic); + let normal = -Vec3::Z; + let d = view_z * normal.z; + z_planes.push(Plane::new(normal.extend(d))); + } - { - // reuse existing visible lights Vec, if it exists - let visible_lights = if let Some(visible_lights) = visible_lights.as_mut() { - visible_lights.entities.clear(); - &mut visible_lights.entities - } else { - &mut visible_lights_scratch - }; + let mut update_from_light_intersections = |visible_lights: &mut Vec| { for light in lights.iter() { let light_sphere = Sphere { center: Vec3A::from(light.translation), @@ -1005,31 +974,186 @@ pub(crate) fn assign_lights_to_clusters( let (min_cluster, max_cluster) = (min_cluster.min(max_cluster), min_cluster.max(max_cluster)); - for y in min_cluster.y..=max_cluster.y { - let row_offset = y * clusters.dimensions.x; - for x in min_cluster.x..=max_cluster.x { - let col_offset = (row_offset + x) * clusters.dimensions.z; - for z in min_cluster.z..=max_cluster.z { - // NOTE: cluster_index = (y * dim.x + x) * dim.z + z - let cluster_index = (col_offset + z) as usize; - let cluster_aabb = &clusters.aabbs[cluster_index]; - if light_sphere.intersects_obb(cluster_aabb, &view_transform) { - clusters.lights[cluster_index].entities.push(light.entity); + // What follows is the Iterative Sphere Refinement algorithm from Just Cause 3 + // Persson et al, Practical Clustered Shading + // http://newq.net/dl/pub/s2015_practical.pdf + // NOTE: A sphere under perspective projection is no longer a sphere. It gets + // stretched and warped, which prevents simpler algorithms from being correct + // as they often assume that the widest part of the sphere under projection is the + // center point on the axis of interest plus the radius, and that is not true! + let view_light_sphere = Sphere { + center: Vec3A::from(inverse_view_transform * light_sphere.center.extend(1.0)), + radius: light_sphere.radius, + }; + let light_center_clip = + camera.projection_matrix * view_light_sphere.center.extend(1.0); + let light_center_ndc = light_center_clip.xyz() / light_center_clip.w; + let cluster_coordinates = ndc_position_to_cluster( + clusters.dimensions, + cluster_factors, + is_orthographic, + light_center_ndc, + view_light_sphere.center.z, + ); + let z_center = if light_center_ndc.z <= 1.0 { + Some(cluster_coordinates.z) + } else { + None + }; + let y_center = if light_center_ndc.y > 1.0 { + None + } else if light_center_ndc.y < -1.0 { + Some(clusters.dimensions.y + 1) + } else { + Some(cluster_coordinates.y) + }; + for z in min_cluster.z..=max_cluster.z { + let mut z_light = view_light_sphere.clone(); + if z_center.is_none() || z != z_center.unwrap() { + // The z plane closer to the light has the larger radius circle where the + // light sphere intersects the z plane. + let z_plane = if z_center.is_some() && z < z_center.unwrap() { + z_planes[(z + 1) as usize] + } else { + z_planes[z as usize] + }; + // Project the sphere to this z plane and use its radius as the radius of a + // new, refined sphere. + if let Some(projected) = project_to_plane_z(z_light, z_plane) { + z_light = projected; + } else { + continue; + } + } + for y in min_cluster.y..=max_cluster.y { + let mut y_light = z_light.clone(); + if y_center.is_none() || y != y_center.unwrap() { + // The y plane closer to the light has the larger radius circle where the + // light sphere intersects the y plane. + let y_plane = if y_center.is_some() && y < y_center.unwrap() { + y_planes[(y + 1) as usize] + } else { + y_planes[y as usize] + }; + // Project the refined sphere to this y plane and use its radius as the + // radius of a new, even more refined sphere. + if let Some(projected) = + project_to_plane_y(y_light, y_plane, is_orthographic) + { + y_light = projected; + } else { + continue; + } + } + // Loop from the left to find the first affected cluster + let mut min_x = min_cluster.x; + loop { + if min_x >= max_cluster.x + || -get_distance_x( + x_planes[(min_x + 1) as usize], + y_light.center, + is_orthographic, + ) + y_light.radius + > 0.0 + { + break; } + min_x += 1; + } + // Loop from the right to find the last affected cluster + let mut max_x = max_cluster.x; + loop { + if max_x <= min_x + || get_distance_x( + x_planes[max_x as usize], + y_light.center, + is_orthographic, + ) + y_light.radius + > 0.0 + { + break; + } + max_x -= 1; + } + let mut cluster_index = ((y * clusters.dimensions.x + min_x) + * clusters.dimensions.z + + z) as usize; + // Mark the clusters in the range as affected + for _ in min_x..=max_x { + clusters.lights[cluster_index].entities.push(light.entity); + cluster_index += clusters.dimensions.z as usize; } } } } - } + }; - if visible_lights.is_none() { - commands.entity(view_entity).insert(VisiblePointLights { - entities: visible_lights_scratch, - }); + // reuse existing visible lights Vec, if it exists + if let Some(visible_lights) = visible_lights.as_mut() { + visible_lights.entities.clear(); + update_from_light_intersections(&mut visible_lights.entities); + } else { + let mut entities = Vec::new(); + update_from_light_intersections(&mut entities); + commands + .entity(view_entity) + .insert(VisiblePointLights { entities }); } } } +// NOTE: This exploits the fact that a x-plane normal has only x and z components +fn get_distance_x(plane: Plane, point: Vec3A, is_orthographic: bool) -> f32 { + if is_orthographic { + point.x - plane.d() + } else { + // Distance from a point to a plane: + // signed distance to plane = (nx * px + ny * py + nz * pz + d) / n.length() + // NOTE: For a x-plane, ny and d are 0 and we have a unit normal + // = nx * px + nz * pz + plane.normal_d().xz().dot(point.xz()) + } +} + +// NOTE: This exploits the fact that a z-plane normal has only a z component +fn project_to_plane_z(z_light: Sphere, z_plane: Plane) -> Option { + // p = sphere center + // n = plane normal + // d = n.p if p is in the plane + // NOTE: For a z-plane, nx and ny are both 0 + // d = px * nx + py * ny + pz * nz + // = pz * nz + // => pz = d / nz + let z = z_plane.d() / z_plane.normal_d().z; + let distance_to_plane = z - z_light.center.z; + if distance_to_plane.abs() > z_light.radius { + return None; + } + Some(Sphere { + center: Vec3A::from(z_light.center.xy().extend(z)), + // hypotenuse length = radius + // pythagorus = (distance to plane)^2 + b^2 = radius^2 + radius: (z_light.radius * z_light.radius - distance_to_plane * distance_to_plane).sqrt(), + }) +} + +// NOTE: This exploits the fact that a y-plane normal has only y and z components +fn project_to_plane_y(y_light: Sphere, y_plane: Plane, is_orthographic: bool) -> Option { + let distance_to_plane = if is_orthographic { + y_plane.d() - y_light.center.y + } else { + -y_light.center.yz().dot(y_plane.normal_d().yz()) + }; + + if distance_to_plane.abs() > y_light.radius { + return None; + } + Some(Sphere { + center: y_light.center + distance_to_plane * y_plane.normal(), + radius: (y_light.radius * y_light.radius - distance_to_plane * distance_to_plane).sqrt(), + }) +} + pub fn update_directional_light_frusta( mut views: Query< ( diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 33cb2eb54d53c..2b1fd83cabe7d 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -220,8 +220,8 @@ impl Plugin for MaterialPlugin { #[derive(Eq, PartialEq, Clone, Hash)] pub struct MaterialPipelineKey { - mesh_key: MeshPipelineKey, - material_key: T, + pub mesh_key: MeshPipelineKey, + pub material_key: T, } pub struct MaterialPipeline { diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index d67773896ebfa..9607289ec9736 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -240,17 +240,19 @@ fn reinhard_extended_luminance(color: vec3, max_white_l: f32) -> vec3 return change_luminance(color, l_new); } +// NOTE: Keep in sync with bevy_pbr/src/light.rs fn view_z_to_z_slice(view_z: f32, is_orthographic: bool) -> u32 { + var z_slice: u32 = 0u; if (is_orthographic) { // NOTE: view_z is correct in the orthographic case - return u32(floor((view_z - lights.cluster_factors.z) * lights.cluster_factors.w)); + z_slice = u32(floor((view_z - lights.cluster_factors.z) * lights.cluster_factors.w)); } else { // NOTE: had to use -view_z to make it positive else log(negative) is nan - return min( - u32(log(-view_z) * lights.cluster_factors.z - lights.cluster_factors.w + 1.0), - lights.cluster_dimensions.z - 1u - ); + z_slice = u32(log(-view_z) * lights.cluster_factors.z - lights.cluster_factors.w + 1.0); } + // NOTE: We use min as we may limit the far z plane used for clustering to be closeer than + // the furthest thing being drawn. This means that we need to limit to the maximum cluster. + return min(z_slice, lights.cluster_dimensions.z - 1u); } fn fragment_cluster_index(frag_coord: vec2, view_z: f32, is_orthographic: bool) -> u32 { diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index e13c28448b5b4..8d74f36495520 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_reflect" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Dynamically interact with rust types" homepage = "https://bevyengine.org" @@ -14,8 +14,8 @@ bevy = ["glam", "smallvec"] [dependencies] # bevy -bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other erased-serde = "0.3" diff --git a/crates/bevy_reflect/bevy_reflect_derive/Cargo.toml b/crates/bevy_reflect/bevy_reflect_derive/Cargo.toml index 08d69d36cd580..46e474c70bc47 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/Cargo.toml +++ b/crates/bevy_reflect/bevy_reflect_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_reflect_derive" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Derive implementations for bevy_reflect" homepage = "https://bevyengine.org" @@ -12,7 +12,7 @@ keywords = ["bevy"] proc-macro = true [dependencies] -bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.7.0-dev" } +bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" } syn = "1.0" proc-macro2 = "1.0" diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index b2edbd9ec43bd..9c182d57382b1 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_render" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides rendering functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -28,18 +28,18 @@ webgl = ["wgpu/webgl"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_crevice = { path = "../bevy_crevice", version = "0.7.0-dev", features = ["glam"] } -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_crevice = { path = "../bevy_crevice", version = "0.8.0-dev", features = ["glam"] } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # rendering image = { version = "0.23.12", default-features = false } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index ca9f69f5cf694..a69892cd22a3a 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -28,7 +28,7 @@ use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use serde::{Deserialize, Serialize}; use wgpu::Extent3d; -#[derive(Component, Default, Debug, Reflect)] +#[derive(Component, Default, Debug, Reflect, Clone)] #[reflect(Component)] pub struct Camera { pub projection_matrix: Mat4, @@ -79,6 +79,7 @@ impl RenderTarget { UVec2::new(width, height) }), } + .filter(|size| size.x > 0 && size.y > 0) } pub fn get_logical_size(&self, windows: &Windows, images: &Assets) -> Option { match self { @@ -312,8 +313,8 @@ pub fn extract_cameras( ExtractedView { projection: camera.projection_matrix, transform: *transform, - width: size.x.max(1), - height: size.y.max(1), + width: size.x, + height: size.y, near: camera.near, far: camera.far, }, diff --git a/crates/bevy_render/src/primitives/mod.rs b/crates/bevy_render/src/primitives/mod.rs index 76c44d2ff0d97..4f1b67555be64 100644 --- a/crates/bevy_render/src/primitives/mod.rs +++ b/crates/bevy_render/src/primitives/mod.rs @@ -58,7 +58,7 @@ impl From for Aabb { } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Sphere { pub center: Vec3A, pub radius: f32, diff --git a/crates/bevy_render/src/texture/texture_cache.rs b/crates/bevy_render/src/texture/texture_cache.rs index 43cac472c154f..d92878774aee7 100644 --- a/crates/bevy_render/src/texture/texture_cache.rs +++ b/crates/bevy_render/src/texture/texture_cache.rs @@ -18,6 +18,7 @@ struct CachedTextureMeta { /// A cached GPU [`Texture`] with corresponding [`TextureView`]. /// This is useful for textures that are created repeatedly (each frame) in the rendering process /// to reduce the amount of GPU memory allocations. +#[derive(Clone)] pub struct CachedTexture { pub texture: Texture, pub default_view: TextureView, diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index ba712a31943cd..e6760974b78cf 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -21,6 +21,7 @@ use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Vec3}; use bevy_transform::components::GlobalTransform; +use bevy_utils::HashMap; pub struct ViewPlugin; @@ -181,26 +182,31 @@ fn prepare_view_targets( mut texture_cache: ResMut, cameras: Query<(Entity, &ExtractedCamera)>, ) { + let mut sampled_textures = HashMap::default(); for (entity, camera) in cameras.iter() { if let Some(size) = camera.physical_size { if let Some(texture_view) = camera.target.get_texture_view(&windows, &images) { let sampled_target = if msaa.samples > 1 { - let sampled_texture = texture_cache.get( - &render_device, - TextureDescriptor { - label: Some("sampled_color_attachment_texture"), - size: Extent3d { - width: size.x, - height: size.y, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: msaa.samples, - dimension: TextureDimension::D2, - format: TextureFormat::bevy_default(), - usage: TextureUsages::RENDER_ATTACHMENT, - }, - ); + let sampled_texture = sampled_textures + .entry(camera.target.clone()) + .or_insert_with(|| { + texture_cache.get( + &render_device, + TextureDescriptor { + label: Some("sampled_color_attachment_texture"), + size: Extent3d { + width: size.x, + height: size.y, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: msaa.samples, + dimension: TextureDimension::D2, + format: TextureFormat::bevy_default(), + usage: TextureUsages::RENDER_ATTACHMENT, + }, + ) + }); Some(sampled_texture.default_view.clone()) } else { None diff --git a/crates/bevy_scene/Cargo.toml b/crates/bevy_scene/Cargo.toml index 4527cdd5445e2..a72240904d096 100644 --- a/crates/bevy_scene/Cargo.toml +++ b/crates/bevy_scene/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_scene" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides scene functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,12 +10,12 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other serde = { version = "1.0", features = ["derive"] } diff --git a/crates/bevy_sprite/Cargo.toml b/crates/bevy_sprite/Cargo.toml index 0a3c9b3604868..9014f99fc8e31 100644 --- a/crates/bevy_sprite/Cargo.toml +++ b/crates/bevy_sprite/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_sprite" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides sprite functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,19 +10,19 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = [ +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = [ "bevy", ] } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other bytemuck = { version = "1.5", features = ["derive"] } diff --git a/crates/bevy_tasks/Cargo.toml b/crates/bevy_tasks/Cargo.toml index 1c3117c181500..7b83b9bc344bd 100644 --- a/crates/bevy_tasks/Cargo.toml +++ b/crates/bevy_tasks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_tasks" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "A task executor for Bevy Engine" homepage = "https://bevyengine.org" diff --git a/crates/bevy_text/Cargo.toml b/crates/bevy_text/Cargo.toml index c7fa8baf80adb..cbfebbae6c69d 100644 --- a/crates/bevy_text/Cargo.toml +++ b/crates/bevy_text/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_text" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides text functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -13,17 +13,17 @@ subpixel_glyph_atlas = [] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_sprite = { path = "../bevy_sprite", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_sprite = { path = "../bevy_sprite", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other anyhow = "1.0.4" diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index 572f9378ca347..6a85ed46064e5 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_transform" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides transform functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,8 +10,8 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev", features = ["bevy_reflect"] } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev"} -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev", features = ["bevy_reflect"] } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev"} +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index cb45d3a65ae40..ea49dbfcf89e7 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_ui" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "A custom ECS-driven UI framework built specifically for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,23 +10,23 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_asset = { path = "../bevy_asset", version = "0.7.0-dev" } -bevy_core = { path = "../bevy_core", version = "0.7.0-dev" } -bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.7.0-dev" } -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.7.0-dev" } -bevy_input = { path = "../bevy_input", version = "0.7.0-dev" } -bevy_log = { path = "../bevy_log", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.7.0-dev", features = ["bevy"] } -bevy_render = { path = "../bevy_render", version = "0.7.0-dev" } -bevy_sprite = { path = "../bevy_sprite", version = "0.7.0-dev" } -bevy_text = { path = "../bevy_text", version = "0.7.0-dev" } -bevy_transform = { path = "../bevy_transform", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" } +bevy_core = { path = "../bevy_core", version = "0.8.0-dev" } +bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.8.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } +bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } +bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_render = { path = "../bevy_render", version = "0.8.0-dev" } +bevy_sprite = { path = "../bevy_sprite", version = "0.8.0-dev" } +bevy_text = { path = "../bevy_text", version = "0.8.0-dev" } +bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other stretch = "0.3.2" diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index daaa8dfa0348b..1cd93e13ca5bc 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_utils" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "A collection of utils for Bevy Engine" homepage = "https://bevyengine.org" @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [dependencies] -bevy_derive = { path = "../bevy_derive", version = "0.7.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" } ahash = "0.7.0" tracing = {version = "0.1", features = ["release_max_level_info"]} instant = { version = "0.1", features = ["wasm-bindgen"] } diff --git a/crates/bevy_window/Cargo.toml b/crates/bevy_window/Cargo.toml index 87e92727245f8..d8bdd76e5bffb 100644 --- a/crates/bevy_window/Cargo.toml +++ b/crates/bevy_window/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_window" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "Provides windowing functionality for Bevy Engine" homepage = "https://bevyengine.org" @@ -10,10 +10,10 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } raw-window-handle = "0.4.2" # other diff --git a/crates/bevy_winit/Cargo.toml b/crates/bevy_winit/Cargo.toml index 51bc1eb58f2da..d4e4eb49d85eb 100644 --- a/crates/bevy_winit/Cargo.toml +++ b/crates/bevy_winit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_winit" -version = "0.7.0-dev" +version = "0.8.0-dev" edition = "2021" description = "A winit window and input backend for Bevy Engine" homepage = "https://bevyengine.org" @@ -14,12 +14,12 @@ x11 = ["winit/x11"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.7.0-dev" } -bevy_ecs = { path = "../bevy_ecs", version = "0.7.0-dev" } -bevy_input = { path = "../bevy_input", version = "0.7.0-dev" } -bevy_math = { path = "../bevy_math", version = "0.7.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.7.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.7.0-dev" } +bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" } +bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.8.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } # other winit = { version = "0.26.0", default-features = false } diff --git a/docs/cargo_features.md b/docs/cargo_features.md index 9d3f44787e818..728a19d6b7e26 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -4,6 +4,7 @@ |feature name|description| |-|-| +|animation|Animation support and glTF animation loading.| |bevy_audio|Audio support. Support for all audio formats depends on this.| |bevy_gilrs|Adds gamepad support.| |bevy_gltf|[glTF](https://www.khronos.org/gltf/) support.| diff --git a/examples/3d/two_passes.rs b/examples/3d/two_passes.rs new file mode 100644 index 0000000000000..f9e9fb8eb045b --- /dev/null +++ b/examples/3d/two_passes.rs @@ -0,0 +1,217 @@ +use bevy::{ + core_pipeline::{draw_3d_graph, node, AlphaMask3d, Opaque3d, Transparent3d}, + prelude::*, + render::{ + camera::{ActiveCamera, Camera, CameraTypePlugin, RenderTarget}, + render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext, SlotValue}, + render_phase::RenderPhase, + renderer::RenderContext, + view::RenderLayers, + RenderApp, RenderStage, + }, + window::WindowId, +}; + +// The name of the final node of the first pass. +pub const FIRST_PASS_DRIVER: &str = "first_pass_driver"; + +// Marks the camera that determines the view rendered in the first pass. +#[derive(Component, Default)] +struct FirstPassCamera; + +fn main() { + let mut app = App::new(); + app.insert_resource(Msaa { samples: 4 }) + .add_plugins(DefaultPlugins) + .add_plugin(CameraTypePlugin::::default()) + .add_startup_system(setup) + .add_system(cube_rotator_system) + .add_system(rotator_system) + .add_system(toggle_msaa); + + let render_app = app.sub_app_mut(RenderApp); + let driver = FirstPassCameraDriver::new(&mut render_app.world); + + // This will add 3D render phases for the new camera. + render_app.add_system_to_stage(RenderStage::Extract, extract_first_pass_camera_phases); + + let mut graph = render_app.world.get_resource_mut::().unwrap(); + + // Add a node for the first pass. + graph.add_node(FIRST_PASS_DRIVER, driver); + + // The first pass's dependencies include those of the main pass. + graph + .add_node_edge(node::MAIN_PASS_DEPENDENCIES, FIRST_PASS_DRIVER) + .unwrap(); + + // Insert the first pass node: CLEAR_PASS_DRIVER -> FIRST_PASS_DRIVER -> MAIN_PASS_DRIVER + graph + .add_node_edge(node::CLEAR_PASS_DRIVER, FIRST_PASS_DRIVER) + .unwrap(); + graph + .add_node_edge(FIRST_PASS_DRIVER, node::MAIN_PASS_DRIVER) + .unwrap(); + app.run(); +} + +// Add 3D render phases for FirstPassCamera. +fn extract_first_pass_camera_phases( + mut commands: Commands, + active: Res>, +) { + if let Some(entity) = active.get() { + commands.get_or_spawn(entity).insert_bundle(( + RenderPhase::::default(), + RenderPhase::::default(), + RenderPhase::::default(), + )); + } +} +// A node for the first pass camera that runs draw_3d_graph with this camera. +struct FirstPassCameraDriver { + query: QueryState>, +} + +impl FirstPassCameraDriver { + pub fn new(render_world: &mut World) -> Self { + Self { + query: QueryState::new(render_world), + } + } +} + +impl Node for FirstPassCameraDriver { + fn update(&mut self, world: &mut World) { + self.query.update_archetypes(world); + } + + fn run( + &self, + graph: &mut RenderGraphContext, + _render_context: &mut RenderContext, + world: &World, + ) -> Result<(), NodeRunError> { + for camera in self.query.iter_manual(world) { + graph.run_sub_graph(draw_3d_graph::NAME, vec![SlotValue::Entity(camera)])?; + } + Ok(()) + } +} + +// Marks the first pass cube. +#[derive(Component)] +struct FirstPassCube; + +// Marks the main pass cube. +#[derive(Component)] +struct MainPassCube; + +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 4.0 })); + let cube_material_handle = materials.add(StandardMaterial { + base_color: Color::GREEN, + reflectance: 0.02, + unlit: false, + ..Default::default() + }); + + let split = 2.0; + + // This specifies the layer used for the first pass, which will be attached to the first pass camera and cube. + let first_pass_layer = RenderLayers::layer(1); + + // The first pass cube. + commands + .spawn_bundle(PbrBundle { + mesh: cube_handle, + material: cube_material_handle, + transform: Transform::from_translation(Vec3::new(-split, 0.0, 1.0)), + ..Default::default() + }) + .insert(FirstPassCube) + .insert(first_pass_layer); + + // Light + // NOTE: Currently lights are shared between passes - see https://github.com/bevyengine/bevy/issues/3462 + commands.spawn_bundle(PointLightBundle { + transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10.0)), + ..Default::default() + }); + + // First pass camera + commands + .spawn_bundle(PerspectiveCameraBundle:: { + camera: Camera { + target: RenderTarget::Window(WindowId::primary()), + ..Default::default() + }, + transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0)) + .looking_at(Vec3::default(), Vec3::Y), + ..PerspectiveCameraBundle::new() + }) + .insert(first_pass_layer); + + let cube_size = 4.0; + let cube_handle = meshes.add(Mesh::from(shape::Box::new(cube_size, cube_size, cube_size))); + + let material_handle = materials.add(StandardMaterial { + base_color: Color::RED, + reflectance: 0.02, + unlit: false, + ..Default::default() + }); + + // Main pass cube. + commands + .spawn_bundle(PbrBundle { + mesh: cube_handle, + material: material_handle, + transform: Transform { + translation: Vec3::new(split, 0.0, -4.5), + rotation: Quat::from_rotation_x(-std::f32::consts::PI / 5.0), + ..Default::default() + }, + ..Default::default() + }) + .insert(MainPassCube); + + // The main pass camera. + commands.spawn_bundle(PerspectiveCameraBundle { + transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0)) + .looking_at(Vec3::default(), Vec3::Y), + ..Default::default() + }); +} + +/// Rotates the inner cube (first pass) +fn rotator_system(time: Res