Implementing Reflect on *MeshBuilder types (#17600)

# Objective

- Most of the `*MeshBuilder` classes are not implementing `Reflect`

## Solution

- Implementing `Reflect` for all `*MeshBuilder` were is possible.
- Make sure all `*MeshBuilder` implements `Default`.
- Adding new `MeshBuildersPlugin` that registers all `*MeshBuilder`
types.

## Testing

- `cargo run -p ci`
- Tested some examples like `3d_scene` just in case something was
broken.
This commit is contained in:
Erick Z 2025-02-03 22:53:51 +01:00 committed by GitHub
parent f22ea72db0
commit b978b13a7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 132 additions and 17 deletions

View File

@ -12,10 +12,12 @@ use bevy_math::{
}, },
FloatExt, Vec2, FloatExt, Vec2,
}; };
use bevy_reflect::prelude::*;
use wgpu_types::PrimitiveTopology; use wgpu_types::PrimitiveTopology;
/// A builder used for creating a [`Mesh`] with a [`Circle`] shape. /// A builder used for creating a [`Mesh`] with a [`Circle`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircleMeshBuilder { pub struct CircleMeshBuilder {
/// The [`Circle`] shape. /// The [`Circle`] shape.
pub circle: Circle, pub circle: Circle,
@ -98,7 +100,8 @@ impl From<Circle> for Mesh {
/// It's expected that more will be added in the future, such as a variant that causes the texture to be /// It's expected that more will be added in the future, such as a variant that causes the texture to be
/// scaled to fit the bounding box of the shape, which would be good for packed textures only including the /// scaled to fit the bounding box of the shape, which would be good for packed textures only including the
/// portion of the circle that is needed to display. /// portion of the circle that is needed to display.
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq, Reflect)]
#[reflect(Default, Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum CircularMeshUvMode { pub enum CircularMeshUvMode {
/// Treats the shape as a mask over a circle of equal size and radius, /// Treats the shape as a mask over a circle of equal size and radius,
@ -119,7 +122,8 @@ impl Default for CircularMeshUvMode {
/// ///
/// The resulting mesh will have a UV-map such that the center of the circle is /// The resulting mesh will have a UV-map such that the center of the circle is
/// at the center of the texture. /// at the center of the texture.
#[derive(Clone, Debug)] #[derive(Clone, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircularSectorMeshBuilder { pub struct CircularSectorMeshBuilder {
/// The sector shape. /// The sector shape.
pub sector: CircularSector, pub sector: CircularSector,
@ -256,7 +260,8 @@ impl From<CircularSector> for Mesh {
/// ///
/// The resulting mesh will have a UV-map such that the center of the circle is /// The resulting mesh will have a UV-map such that the center of the circle is
/// at the center of the texture. /// at the center of the texture.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CircularSegmentMeshBuilder { pub struct CircularSegmentMeshBuilder {
/// The segment shape. /// The segment shape.
pub segment: CircularSegment, pub segment: CircularSegment,
@ -402,6 +407,8 @@ impl From<CircularSegment> for Mesh {
/// ///
/// You must verify that the `vertices` are not concave when constructing this type. You can /// You must verify that the `vertices` are not concave when constructing this type. You can
/// guarantee this by creating a [`ConvexPolygon`] first, then calling [`ConvexPolygon::mesh()`]. /// guarantee this by creating a [`ConvexPolygon`] first, then calling [`ConvexPolygon::mesh()`].
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Debug)]
pub struct ConvexPolygonMeshBuilder<const N: usize> { pub struct ConvexPolygonMeshBuilder<const N: usize> {
pub vertices: [Vec2; N], pub vertices: [Vec2; N],
} }
@ -451,11 +458,23 @@ impl<const N: usize> From<ConvexPolygon<N>> for Mesh {
} }
/// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape. /// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RegularPolygonMeshBuilder { pub struct RegularPolygonMeshBuilder {
circumradius: f32, circumradius: f32,
sides: u32, sides: u32,
} }
impl Default for RegularPolygonMeshBuilder {
/// Returns the default [`RegularPolygonMeshBuilder`] with six sides (a hexagon) and a circumradius of `0.5`.
fn default() -> Self {
Self {
circumradius: 0.5,
sides: 6,
}
}
}
impl RegularPolygonMeshBuilder { impl RegularPolygonMeshBuilder {
/// Creates a new [`RegularPolygonMeshBuilder`] from the radius of a circumcircle and a number /// Creates a new [`RegularPolygonMeshBuilder`] from the radius of a circumcircle and a number
/// of sides. /// of sides.
@ -513,7 +532,8 @@ impl From<RegularPolygon> for Mesh {
} }
/// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. /// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct EllipseMeshBuilder { pub struct EllipseMeshBuilder {
/// The [`Ellipse`] shape. /// The [`Ellipse`] shape.
pub ellipse: Ellipse, pub ellipse: Ellipse,
@ -617,6 +637,8 @@ impl From<Ellipse> for Mesh {
} }
/// A builder for creating a [`Mesh`] with an [`Annulus`] shape. /// A builder for creating a [`Mesh`] with an [`Annulus`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct AnnulusMeshBuilder { pub struct AnnulusMeshBuilder {
/// The [`Annulus`] shape. /// The [`Annulus`] shape.
pub annulus: Annulus, pub annulus: Annulus,
@ -747,10 +769,22 @@ impl From<Annulus> for Mesh {
} }
} }
/// A builder for creating a [`Mesh`] with an [`Rhombus`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RhombusMeshBuilder { pub struct RhombusMeshBuilder {
half_diagonals: Vec2, half_diagonals: Vec2,
} }
impl Default for RhombusMeshBuilder {
/// Returns the default [`RhombusMeshBuilder`] with a half-horizontal and half-vertical diagonal of `0.5`.
fn default() -> Self {
Self {
half_diagonals: Vec2::splat(0.5),
}
}
}
impl RhombusMeshBuilder { impl RhombusMeshBuilder {
/// Creates a new [`RhombusMeshBuilder`] from a horizontal and vertical diagonal size. /// Creates a new [`RhombusMeshBuilder`] from a horizontal and vertical diagonal size.
/// ///
@ -822,6 +856,8 @@ impl From<Rhombus> for Mesh {
} }
/// A builder used for creating a [`Mesh`] with a [`Triangle2d`] shape. /// A builder used for creating a [`Mesh`] with a [`Triangle2d`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct Triangle2dMeshBuilder { pub struct Triangle2dMeshBuilder {
triangle: Triangle2d, triangle: Triangle2d,
} }
@ -897,10 +933,21 @@ impl From<Triangle2d> for Mesh {
} }
/// A builder used for creating a [`Mesh`] with a [`Rectangle`] shape. /// A builder used for creating a [`Mesh`] with a [`Rectangle`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct RectangleMeshBuilder { pub struct RectangleMeshBuilder {
half_size: Vec2, half_size: Vec2,
} }
impl Default for RectangleMeshBuilder {
/// Returns the default [`RectangleMeshBuilder`] with a half-width and half-height of `0.5`.
fn default() -> Self {
Self {
half_size: Vec2::splat(0.5),
}
}
}
impl RectangleMeshBuilder { impl RectangleMeshBuilder {
/// Creates a new [`RectangleMeshBuilder`] from a full width and height. /// Creates a new [`RectangleMeshBuilder`] from a full width and height.
/// ///
@ -966,7 +1013,8 @@ impl From<Rectangle> for Mesh {
} }
/// A builder used for creating a [`Mesh`] with a [`Capsule2d`] shape. /// A builder used for creating a [`Mesh`] with a [`Capsule2d`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct Capsule2dMeshBuilder { pub struct Capsule2dMeshBuilder {
/// The [`Capsule2d`] shape. /// The [`Capsule2d`] shape.
pub capsule: Capsule2d, pub capsule: Capsule2d,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Capsule3d, Vec2, Vec3}; use bevy_math::{ops, primitives::Capsule3d, Vec2, Vec3};
use bevy_reflect::prelude::*;
/// Manner in which UV coordinates are distributed vertically. /// Manner in which UV coordinates are distributed vertically.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum CapsuleUvProfile { pub enum CapsuleUvProfile {
/// UV space is distributed by how much of the capsule consists of the hemispheres. /// UV space is distributed by how much of the capsule consists of the hemispheres.
#[default] #[default]
@ -16,7 +18,8 @@ pub enum CapsuleUvProfile {
} }
/// A builder used for creating a [`Mesh`] with a [`Capsule3d`] shape. /// A builder used for creating a [`Mesh`] with a [`Capsule3d`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct Capsule3dMeshBuilder { pub struct Capsule3dMeshBuilder {
/// The [`Capsule3d`] shape. /// The [`Capsule3d`] shape.
pub capsule: Capsule3d, pub capsule: Capsule3d,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Cone, Vec3}; use bevy_math::{ops, primitives::Cone, Vec3};
use bevy_reflect::prelude::*;
/// Anchoring options for [`ConeMeshBuilder`] /// Anchoring options for [`ConeMeshBuilder`]
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum ConeAnchor { pub enum ConeAnchor {
#[default] #[default]
/// Midpoint between the tip of the cone and the center of its base. /// Midpoint between the tip of the cone and the center of its base.
@ -15,7 +17,8 @@ pub enum ConeAnchor {
} }
/// A builder used for creating a [`Mesh`] with a [`Cone`] shape. /// A builder used for creating a [`Mesh`] with a [`Cone`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct ConeMeshBuilder { pub struct ConeMeshBuilder {
/// The [`Cone`] shape. /// The [`Cone`] shape.
pub cone: Cone, pub cone: Cone,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::ConicalFrustum, Vec3}; use bevy_math::{ops, primitives::ConicalFrustum, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`ConicalFrustum`] shape. /// A builder used for creating a [`Mesh`] with a [`ConicalFrustum`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct ConicalFrustumMeshBuilder { pub struct ConicalFrustumMeshBuilder {
/// The [`ConicalFrustum`] shape. /// The [`ConicalFrustum`] shape.
pub frustum: ConicalFrustum, pub frustum: ConicalFrustum,

View File

@ -1,12 +1,24 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Cuboid, Vec3}; use bevy_math::{primitives::Cuboid, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Cuboid`] shape. /// A builder used for creating a [`Mesh`] with a [`Cuboid`] shape.
#[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CuboidMeshBuilder { pub struct CuboidMeshBuilder {
half_size: Vec3, half_size: Vec3,
} }
impl Default for CuboidMeshBuilder {
/// Returns the default [`CuboidMeshBuilder`] with a width, height, and depth of `1.0`.
fn default() -> Self {
Self {
half_size: Vec3::splat(0.5),
}
}
}
impl MeshBuilder for CuboidMeshBuilder { impl MeshBuilder for CuboidMeshBuilder {
fn build(&self) -> Mesh { fn build(&self) -> Mesh {
let min = -self.half_size; let min = -self.half_size;

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Cylinder}; use bevy_math::{ops, primitives::Cylinder};
use bevy_reflect::prelude::*;
/// Anchoring options for [`CylinderMeshBuilder`] /// Anchoring options for [`CylinderMeshBuilder`]
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default, Reflect)]
#[reflect(Default, Debug)]
pub enum CylinderAnchor { pub enum CylinderAnchor {
#[default] #[default]
/// Midpoint between the top and bottom caps of the cylinder /// Midpoint between the top and bottom caps of the cylinder
@ -15,7 +17,8 @@ pub enum CylinderAnchor {
} }
/// A builder used for creating a [`Mesh`] with a [`Cylinder`] shape. /// A builder used for creating a [`Mesh`] with a [`Cylinder`] shape.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct CylinderMeshBuilder { pub struct CylinderMeshBuilder {
/// The [`Cylinder`] shape. /// The [`Cylinder`] shape.
pub cylinder: Cylinder, pub cylinder: Cylinder,

View File

@ -1,9 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3}; use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Plane3d`] shape. /// A builder used for creating a [`Mesh`] with a [`Plane3d`] shape.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct PlaneMeshBuilder { pub struct PlaneMeshBuilder {
/// The [`Plane3d`] shape. /// The [`Plane3d`] shape.
pub plane: Plane3d, pub plane: Plane3d,

View File

@ -1,6 +1,7 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Sphere}; use bevy_math::{ops, primitives::Sphere};
use bevy_reflect::prelude::*;
use core::f32::consts::PI; use core::f32::consts::PI;
use hexasphere::shapes::IcoSphere; use hexasphere::shapes::IcoSphere;
use thiserror::Error; use thiserror::Error;
@ -19,7 +20,8 @@ pub enum IcosphereError {
} }
/// A type of sphere mesh. /// A type of sphere mesh.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, Reflect)]
#[reflect(Default, Debug)]
pub enum SphereKind { pub enum SphereKind {
/// An icosphere, a spherical mesh that consists of similar sized triangles. /// An icosphere, a spherical mesh that consists of similar sized triangles.
Ico { Ico {
@ -46,7 +48,8 @@ impl Default for SphereKind {
} }
/// A builder used for creating a [`Mesh`] with an [`Sphere`] shape. /// A builder used for creating a [`Mesh`] with an [`Sphere`] shape.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct SphereMeshBuilder { pub struct SphereMeshBuilder {
/// The [`Sphere`] shape. /// The [`Sphere`] shape.
pub sphere: Sphere, pub sphere: Sphere,

View File

@ -2,8 +2,11 @@ use super::triangle3d;
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::primitives::{Tetrahedron, Triangle3d}; use bevy_math::primitives::{Tetrahedron, Triangle3d};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Tetrahedron`] shape. /// A builder used for creating a [`Mesh`] with a [`Tetrahedron`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct TetrahedronMeshBuilder { pub struct TetrahedronMeshBuilder {
tetrahedron: Tetrahedron, tetrahedron: Tetrahedron,
} }

View File

@ -1,10 +1,12 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{ops, primitives::Torus, Vec3}; use bevy_math::{ops, primitives::Torus, Vec3};
use bevy_reflect::prelude::*;
use core::ops::RangeInclusive; use core::ops::RangeInclusive;
/// A builder used for creating a [`Mesh`] with a [`Torus`] shape. /// A builder used for creating a [`Mesh`] with a [`Torus`] shape.
#[derive(Clone, Debug)] #[derive(Clone, Debug, Reflect)]
#[reflect(Default, Debug)]
pub struct TorusMeshBuilder { pub struct TorusMeshBuilder {
/// The [`Torus`] shape. /// The [`Torus`] shape.
pub torus: Torus, pub torus: Torus,

View File

@ -1,8 +1,11 @@
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
use bevy_asset::RenderAssetUsages; use bevy_asset::RenderAssetUsages;
use bevy_math::{primitives::Triangle3d, Vec3}; use bevy_math::{primitives::Triangle3d, Vec3};
use bevy_reflect::prelude::*;
/// A builder used for creating a [`Mesh`] with a [`Triangle3d`] shape. /// A builder used for creating a [`Mesh`] with a [`Triangle3d`] shape.
#[derive(Clone, Copy, Debug, Default, Reflect)]
#[reflect(Default, Debug)]
pub struct Triangle3dMeshBuilder { pub struct Triangle3dMeshBuilder {
triangle: Triangle3d, triangle: Triangle3d,
} }

View File

@ -24,6 +24,36 @@ use bevy_ecs::{
pub use components::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh2d, Mesh3d}; pub use components::{mark_3d_meshes_as_changed_if_their_assets_changed, Mesh2d, Mesh3d};
use wgpu::IndexFormat; use wgpu::IndexFormat;
/// Registers all [`MeshBuilder`] types.
pub struct MeshBuildersPlugin;
impl Plugin for MeshBuildersPlugin {
fn build(&self, app: &mut App) {
// 2D Mesh builders
app.register_type::<CircleMeshBuilder>()
.register_type::<CircularSectorMeshBuilder>()
.register_type::<CircularSegmentMeshBuilder>()
.register_type::<RegularPolygonMeshBuilder>()
.register_type::<EllipseMeshBuilder>()
.register_type::<AnnulusMeshBuilder>()
.register_type::<RhombusMeshBuilder>()
.register_type::<Triangle2dMeshBuilder>()
.register_type::<RectangleMeshBuilder>()
.register_type::<Capsule2dMeshBuilder>()
// 3D Mesh builders
.register_type::<Capsule3dMeshBuilder>()
.register_type::<ConeMeshBuilder>()
.register_type::<ConicalFrustumMeshBuilder>()
.register_type::<CuboidMeshBuilder>()
.register_type::<CylinderMeshBuilder>()
.register_type::<PlaneMeshBuilder>()
.register_type::<SphereMeshBuilder>()
.register_type::<TetrahedronMeshBuilder>()
.register_type::<TorusMeshBuilder>()
.register_type::<Triangle3dMeshBuilder>();
}
}
/// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU. /// Adds the [`Mesh`] as an asset and makes sure that they are extracted and prepared for the GPU.
pub struct MeshPlugin; pub struct MeshPlugin;
@ -35,6 +65,7 @@ impl Plugin for MeshPlugin {
.register_type::<Mesh3d>() .register_type::<Mesh3d>()
.register_type::<skinning::SkinnedMesh>() .register_type::<skinning::SkinnedMesh>()
.register_type::<Vec<Entity>>() .register_type::<Vec<Entity>>()
.add_plugins(MeshBuildersPlugin)
// 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready // 'Mesh' must be prepared after 'Image' as meshes rely on the morph target image being ready
.add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default()) .add_plugins(RenderAssetPlugin::<RenderMesh, GpuImage>::default())
.add_plugins(MeshAllocatorPlugin) .add_plugins(MeshAllocatorPlugin)