Skip to content

Commit

Permalink
Improve plugin_group macro documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
doonv committed Jan 21, 2024
1 parent 84b6282 commit 4c8b853
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 30 deletions.
10 changes: 6 additions & 4 deletions crates/bevy_app/src/plugin_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ use std::any::TypeId;
/// # }
/// plugin_group!(
/// PhysicsPlugins {
/// // Due to local ambiguity issues,
/// // you have to use 3 semicolons for the last part of the path
/// velocity:::VelocityPlugin,
/// collision::capsule:::CapsuleCollisionPlugin,
/// // Due to local ambiguity issues, you have to
/// // use a semicolon before the plugin's name.
/// :TickratePlugin,
/// // Due to local ambiguity issues, you have to
/// // use 3 semicolons for the last part of the path.
/// collision::capsule:::CapsuleCollisionPlugin,
/// velocity:::VelocityPlugin,
/// #[cfg(feature = "external_forces")]
/// features:::ForcePlugin,
/// // You can add any attribute you want like this, but it won't be documented.
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_core/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use std::{
ops::Deref,
};

#[cfg(feature = "serialize")]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

/// Component used to identify an entity. Stores a hash for faster comparisons.
///
/// The hash is eagerly re-computed upon each update to the name.
Expand All @@ -19,8 +22,9 @@ use std::{
/// used instead as the default unique identifier.
#[derive(Reflect, Component, Clone)]
#[reflect(Component, Default, Debug)]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
pub struct Name {
hash: u64, // TODO: Shouldn't be serialized
hash: u64, // Won't be serialized (see: `bevy_core::serde` module)
name: Cow<'static, str>,
}

Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_gizmos/src/circles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! and assorted support items.
use crate::prelude::{GizmoConfigGroup, Gizmos};
use bevy_math::{Quat, Vec2, Vec3};
use bevy_math::{primitives::Direction3d, Quat, Vec2, Vec3};
use bevy_render::color::Color;
use std::f32::consts::TAU;

Expand All @@ -28,12 +28,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.circle(Vec3::ZERO, Vec3::Z, 1., Color::GREEN);
/// gizmos.circle(Vec3::ZERO, Direction3d::Z, 1., Color::GREEN);
///
/// // Circles have 32 line-segments by default.
/// // You may want to increase this for larger circles.
/// gizmos
/// .circle(Vec3::ZERO, Vec3::Z, 5., Color::RED)
/// .circle(Vec3::ZERO, Direction3d::Z, 5., Color::RED)
/// .segments(64);
/// }
/// # bevy_ecs::system::assert_is_system(system);
Expand All @@ -42,7 +42,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
pub fn circle(
&mut self,
position: Vec3,
normal: Vec3,
normal: Direction3d,
radius: f32,
color: Color,
) -> CircleBuilder<'_, 'w, 's, T> {
Expand Down Expand Up @@ -97,7 +97,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
pub struct CircleBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
gizmos: &'a mut Gizmos<'w, 's, T>,
position: Vec3,
normal: Vec3,
normal: Direction3d,
radius: f32,
color: Color,
segments: usize,
Expand All @@ -116,7 +116,7 @@ impl<T: GizmoConfigGroup> Drop for CircleBuilder<'_, '_, '_, T> {
if !self.gizmos.enabled {
return;
}
let rotation = Quat::from_rotation_arc(Vec3::Z, self.normal);
let rotation = Quat::from_rotation_arc(Vec3::Z, *self.normal);
let positions = circle_inner(self.radius, self.segments)
.map(|vec2| self.position + rotation * vec2.extend(0.));
self.gizmos.linestrip(positions, self.color);
Expand Down
9 changes: 7 additions & 2 deletions crates/bevy_gizmos/src/gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_ecs::{
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use bevy_math::{Mat2, Quat, Vec2, Vec3};
use bevy_math::{primitives::Direction3d, Mat2, Quat, Vec2, Vec3};
use bevy_render::color::Color;
use bevy_transform::TransformPoint;

Expand Down Expand Up @@ -618,7 +618,12 @@ impl<T: GizmoConfigGroup> Drop for SphereBuilder<'_, '_, '_, T> {
}
for axis in Vec3::AXES {
self.gizmos
.circle(self.position, self.rotation * axis, self.radius, self.color)
.circle(
self.position,
Direction3d::new_unchecked(self.rotation * axis),
self.radius,
self.color,
)
.segments(self.circle_segments);
}
}
Expand Down
119 changes: 119 additions & 0 deletions crates/bevy_render/macros/src/as_bind_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use syn::{

const UNIFORM_ATTRIBUTE_NAME: Symbol = Symbol("uniform");
const TEXTURE_ATTRIBUTE_NAME: Symbol = Symbol("texture");
const STORAGE_TEXTURE_ATTRIBUTE_NAME: Symbol = Symbol("storage_texture");
const SAMPLER_ATTRIBUTE_NAME: Symbol = Symbol("sampler");
const STORAGE_ATTRIBUTE_NAME: Symbol = Symbol("storage");
const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data");
Expand All @@ -19,6 +20,7 @@ const BIND_GROUP_DATA_ATTRIBUTE_NAME: Symbol = Symbol("bind_group_data");
enum BindingType {
Uniform,
Texture,
StorageTexture,
Sampler,
Storage,
}
Expand Down Expand Up @@ -133,6 +135,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
BindingType::Uniform
} else if attr_ident == TEXTURE_ATTRIBUTE_NAME {
BindingType::Texture
} else if attr_ident == STORAGE_TEXTURE_ATTRIBUTE_NAME {
BindingType::StorageTexture
} else if attr_ident == SAMPLER_ATTRIBUTE_NAME {
BindingType::Sampler
} else if attr_ident == STORAGE_ATTRIBUTE_NAME {
Expand Down Expand Up @@ -255,6 +259,45 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
}
});
}
BindingType::StorageTexture => {
let StorageTextureAttrs {
dimension,
image_format,
access,
visibility,
} = get_storage_texture_binding_attr(nested_meta_items)?;

let visibility =
visibility.hygienic_quote(&quote! { #render_path::render_resource });

let fallback_image = get_fallback_image(&render_path, dimension);

binding_impls.push(quote! {
( #binding_index,
#render_path::render_resource::OwnedBindingResource::TextureView({
let handle: Option<&#asset_path::Handle<#render_path::texture::Image>> = (&self.#field_name).into();
if let Some(handle) = handle {
images.get(handle).ok_or_else(|| #render_path::render_resource::AsBindGroupError::RetryNextUpdate)?.texture_view.clone()
} else {
#fallback_image.texture_view.clone()
}
})
)
});

binding_layouts.push(quote! {
#render_path::render_resource::BindGroupLayoutEntry {
binding: #binding_index,
visibility: #visibility,
ty: #render_path::render_resource::BindingType::StorageTexture {
access: #render_path::render_resource::StorageTextureAccess::#access,
format: #render_path::render_resource::TextureFormat::#image_format,
view_dimension: #render_path::render_resource::#dimension,
},
count: None,
}
});
}
BindingType::Texture => {
let TextureAttrs {
dimension,
Expand Down Expand Up @@ -585,6 +628,10 @@ impl ShaderStageVisibility {
fn vertex_fragment() -> Self {
Self::Flags(VisibilityFlags::vertex_fragment())
}

fn compute() -> Self {
Self::Flags(VisibilityFlags::compute())
}
}

impl VisibilityFlags {
Expand All @@ -595,6 +642,13 @@ impl VisibilityFlags {
..Default::default()
}
}

fn compute() -> Self {
Self {
compute: true,
..Default::default()
}
}
}

impl ShaderStageVisibility {
Expand Down Expand Up @@ -741,7 +795,72 @@ impl Default for TextureAttrs {
}
}

struct StorageTextureAttrs {
dimension: BindingTextureDimension,
// Parsing of the image_format parameter is deferred to the type checker,
// which will error if the format is not member of the TextureFormat enum.
image_format: proc_macro2::TokenStream,
// Parsing of the access parameter is deferred to the type checker,
// which will error if the access is not member of the StorageTextureAccess enum.
access: proc_macro2::TokenStream,
visibility: ShaderStageVisibility,
}

impl Default for StorageTextureAttrs {
fn default() -> Self {
Self {
dimension: Default::default(),
image_format: quote! { Rgba8Unorm },
access: quote! { ReadWrite },
visibility: ShaderStageVisibility::compute(),
}
}
}

fn get_storage_texture_binding_attr(metas: Vec<Meta>) -> Result<StorageTextureAttrs> {
let mut storage_texture_attrs = StorageTextureAttrs::default();

for meta in metas {
use syn::Meta::{List, NameValue};
match meta {
// Parse #[storage_texture(0, dimension = "...")].
NameValue(m) if m.path == DIMENSION => {
let value = get_lit_str(DIMENSION, &m.value)?;
storage_texture_attrs.dimension = get_texture_dimension_value(value)?;
}
// Parse #[storage_texture(0, format = ...))].
NameValue(m) if m.path == IMAGE_FORMAT => {
storage_texture_attrs.image_format = m.value.into_token_stream();
}
// Parse #[storage_texture(0, access = ...))].
NameValue(m) if m.path == ACCESS => {
storage_texture_attrs.access = m.value.into_token_stream();
}
// Parse #[storage_texture(0, visibility(...))].
List(m) if m.path == VISIBILITY => {
storage_texture_attrs.visibility = get_visibility_flag_value(&m)?;
}
NameValue(m) => {
return Err(Error::new_spanned(
m.path,
"Not a valid name. Available attributes: `dimension`, `image_format`, `access`.",
));
}
_ => {
return Err(Error::new_spanned(
meta,
"Not a name value pair: `foo = \"...\"`",
));
}
}
}

Ok(storage_texture_attrs)
}

const DIMENSION: Symbol = Symbol("dimension");
const IMAGE_FORMAT: Symbol = Symbol("image_format");
const ACCESS: Symbol = Symbol("access");
const SAMPLE_TYPE: Symbol = Symbol("sample_type");
const FILTERABLE: Symbol = Symbol("filterable");
const MULTISAMPLED: Symbol = Symbol("multisampled");
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_render/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub fn derive_extract_component(input: TokenStream) -> TokenStream {

#[proc_macro_derive(
AsBindGroup,
attributes(uniform, texture, sampler, bind_group_data, storage)
attributes(uniform, storage_texture, texture, sampler, bind_group_data, storage)
)]
pub fn derive_as_bind_group(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down
16 changes: 16 additions & 0 deletions crates/bevy_render/src/render_resource/bind_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ impl Deref for BindGroup {
/// values: Vec<f32>,
/// #[storage(4, read_only, buffer)]
/// buffer: Buffer,
/// #[storage_texture(5)]
/// storage_texture: Handle<Image>,
/// }
/// ```
///
Expand All @@ -97,6 +99,7 @@ impl Deref for BindGroup {
/// @group(2) @binding(1) var color_texture: texture_2d<f32>;
/// @group(2) @binding(2) var color_sampler: sampler;
/// @group(2) @binding(3) var<storage> values: array<f32>;
/// @group(2) @binding(5) var storage_texture: texture_storage_2d<rgba8unorm, read_write>;
/// ```
/// Note that the "group" index is determined by the usage context. It is not defined in [`AsBindGroup`]. For example, in Bevy material bind groups
/// are generally bound to group 2.
Expand All @@ -123,6 +126,19 @@ impl Deref for BindGroup {
/// | `multisampled` = ... | `true`, `false` | `false` |
/// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `vertex`, `fragment` |
///
/// * `storage_texture(BINDING_INDEX, arguments)`
/// * This field's [`Handle<Image>`](bevy_asset::Handle) will be used to look up the matching [`Texture`](crate::render_resource::Texture)
/// GPU resource, which will be bound as a storage texture in shaders. The field will be assumed to implement [`Into<Option<Handle<Image>>>`]. In practice,
/// most fields should be a [`Handle<Image>`](bevy_asset::Handle) or [`Option<Handle<Image>>`]. If the value of an [`Option<Handle<Image>>`] is
/// [`None`], the [`FallbackImage`] resource will be used instead.
///
/// | Arguments | Values | Default |
/// |------------------------|--------------------------------------------------------------------------------------------|---------------|
/// | `dimension` = "..." | `"1d"`, `"2d"`, `"2d_array"`, `"3d"`, `"cube"`, `"cube_array"` | `"2d"` |
/// | `image_format` = ... | any member of [`TextureFormat`](crate::render_resource::TextureFormat) | `Rgba8Unorm` |
/// | `access` = ... | any member of [`StorageTextureAccess`](crate::render_resource::StorageTextureAccess) | `ReadWrite` |
/// | `visibility(...)` | `all`, `none`, or a list-combination of `vertex`, `fragment`, `compute` | `compute` |
///
/// * `sampler(BINDING_INDEX, arguments)`
/// * This field's [`Handle<Image>`](bevy_asset::Handle) will be used to look up the matching [`Sampler`] GPU
/// resource, which will be bound as a sampler in shaders. The field will be assumed to implement [`Into<Option<Handle<Image>>>`]. In practice,
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_tasks/src/task_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ impl TaskPool {
unsafe { mem::transmute(external_executor) };
// SAFETY: As above, all futures must complete in this function so we can change the lifetime
let scope_executor: &'env ThreadExecutor<'env> = unsafe { mem::transmute(scope_executor) };
let spawned: ConcurrentQueue<FallibleTask<T>> = ConcurrentQueue::unbounded();
let spawned: ConcurrentQueue<FallibleTask<Result<T, Box<(dyn std::any::Any + Send)>>>> =
ConcurrentQueue::unbounded();
// shadow the variable so that the owned value cannot be used for the rest of the function
// SAFETY: As above, all futures must complete in this function so we can change the lifetime
let spawned: &'env ConcurrentQueue<
Expand Down
5 changes: 3 additions & 2 deletions examples/3d/3d_gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::f32::consts::PI;

use bevy::math::primitives::Direction3d;
use bevy::prelude::*;

fn main() {
Expand Down Expand Up @@ -96,10 +97,10 @@ fn system(mut gizmos: Gizmos, mut my_gizmos: Gizmos<MyRoundGizmos>, time: Res<Ti
}

// Circles have 32 line-segments by default.
my_gizmos.circle(Vec3::ZERO, Vec3::Y, 3., Color::BLACK);
my_gizmos.circle(Vec3::ZERO, Direction3d::Y, 3., Color::BLACK);
// You may want to increase this for larger circles or spheres.
my_gizmos
.circle(Vec3::ZERO, Vec3::Y, 3.1, Color::NAVY)
.circle(Vec3::ZERO, Direction3d::Y, 3.1, Color::NAVY)
.segments(64);
my_gizmos
.sphere(Vec3::ZERO, Quat::IDENTITY, 3.2, Color::BLACK)
Expand Down
8 changes: 7 additions & 1 deletion examples/3d/3d_viewport_to_world.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! This example demonstrates how to use the `Camera::viewport_to_world` method.
use bevy::math::primitives::Direction3d;
use bevy::prelude::*;

fn main() {
Expand Down Expand Up @@ -36,7 +37,12 @@ fn draw_cursor(
let point = ray.get_point(distance);

// Draw a circle just above the ground plane at that position.
gizmos.circle(point + ground.up() * 0.01, ground.up(), 0.2, Color::WHITE);
gizmos.circle(
point + ground.up() * 0.01,
Direction3d::new_unchecked(ground.up()), // Up vector is already normalized.
0.2,
Color::WHITE,
);
}

#[derive(Component)]
Expand Down
Loading

0 comments on commit 4c8b853

Please sign in to comment.