From 450a9202d0711a12ae6ac0cb801ebe56deeaed53 Mon Sep 17 00:00:00 2001 From: Lynn <62256001+solis-lumine-vorago@users.noreply.github.com> Date: Sat, 18 May 2024 13:58:11 +0200 Subject: [PATCH] Common `MeshBuilder` trait (#13411) # Objective - All `ShapeMeshBuilder`s have some methods/implementations in common. These are `fn build(&self) -> Mesh` and this implementation: ```rust impl From for Mesh { fn from(builder: ShapeMeshBuilder) -> { builder.build() } } ``` - For the sake of consistency, these can be moved into a shared trait ## Solution - Add `trait MeshBuilder` containing a `fn build(&self) -> Mesh` and implementing `MeshBuilder for ShapeMeshBuilder` - Implement `From for Mesh` ## Migration Guide - When calling `.build()` you need to import `bevy_render::mesh::primitives::MeshBuilder` --- crates/bevy_render/src/lib.rs | 2 +- .../bevy_render/src/mesh/primitives/dim2.rs | 46 ++++++------------- .../src/mesh/primitives/dim3/capsule.rs | 13 ++---- .../src/mesh/primitives/dim3/cone.rs | 15 ++---- .../src/mesh/primitives/dim3/cylinder.rs | 13 ++---- .../src/mesh/primitives/dim3/plane.rs | 13 ++---- .../src/mesh/primitives/dim3/sphere.rs | 36 +++++++-------- .../src/mesh/primitives/dim3/torus.rs | 13 ++---- crates/bevy_render/src/mesh/primitives/mod.rs | 16 ++++++- 9 files changed, 66 insertions(+), 101 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index dea5f7bb7d..841ed5956c 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -43,7 +43,7 @@ pub mod prelude { Camera, ClearColor, ClearColorConfig, OrthographicProjection, PerspectiveProjection, Projection, }, - mesh::{morph::MorphWeights, primitives::Meshable, Mesh}, + mesh::{morph::MorphWeights, primitives::MeshBuilder, primitives::Meshable, Mesh}, render_resource::Shader, spatial_bundle::SpatialBundle, texture::{image_texture_conversion::IntoDynamicImageError, Image, ImagePlugin}, diff --git a/crates/bevy_render/src/mesh/primitives/dim2.rs b/crates/bevy_render/src/mesh/primitives/dim2.rs index b928a195a2..37a91c7f22 100644 --- a/crates/bevy_render/src/mesh/primitives/dim2.rs +++ b/crates/bevy_render/src/mesh/primitives/dim2.rs @@ -4,7 +4,7 @@ use crate::{ render_asset::RenderAssetUsages, }; -use super::Meshable; +use super::{MeshBuilder, Meshable}; use bevy_math::primitives::{ Annulus, Capsule2d, Circle, Ellipse, Rectangle, RegularPolygon, Triangle2d, Triangle3d, WindingOrder, @@ -48,9 +48,10 @@ impl CircleMeshBuilder { self.resolution = resolution; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for CircleMeshBuilder { + fn build(&self) -> Mesh { RegularPolygon::new(self.circle.radius, self.resolution).mesh() } } @@ -72,12 +73,6 @@ impl From for Mesh { } } -impl From for Mesh { - fn from(circle: CircleMeshBuilder) -> Self { - circle.build() - } -} - impl Meshable for RegularPolygon { type Output = Mesh; @@ -133,9 +128,10 @@ impl EllipseMeshBuilder { self.resolution = resolution; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for EllipseMeshBuilder { + fn build(&self) -> Mesh { let mut indices = Vec::with_capacity((self.resolution - 2) * 3); let mut positions = Vec::with_capacity(self.resolution); let normals = vec![[0.0, 0.0, 1.0]; self.resolution]; @@ -188,12 +184,6 @@ impl From for Mesh { } } -impl From for Mesh { - fn from(ellipse: EllipseMeshBuilder) -> Self { - ellipse.build() - } -} - /// A builder for creating a [`Mesh`] with an [`Annulus`] shape. pub struct AnnulusMeshBuilder { /// The [`Annulus`] shape. @@ -229,9 +219,10 @@ impl AnnulusMeshBuilder { self.resolution = resolution; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for AnnulusMeshBuilder { + fn build(&self) -> Mesh { let inner_radius = self.annulus.inner_circle.radius; let outer_radius = self.annulus.outer_circle.radius; @@ -306,12 +297,6 @@ impl From for Mesh { } } -impl From for Mesh { - fn from(builder: AnnulusMeshBuilder) -> Self { - builder.build() - } -} - impl Meshable for Triangle2d { type Output = Mesh; @@ -423,9 +408,10 @@ impl Capsule2dMeshBuilder { self.resolution = resolution; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for Capsule2dMeshBuilder { + fn build(&self) -> Mesh { // The resolution is the number of vertices for one semicircle let resolution = self.resolution as u32; let vertex_count = 2 * self.resolution; @@ -517,12 +503,6 @@ impl From for Mesh { } } -impl From for Mesh { - fn from(capsule: Capsule2dMeshBuilder) -> Self { - capsule.build() - } -} - #[cfg(test)] mod tests { use bevy_math::primitives::RegularPolygon; diff --git a/crates/bevy_render/src/mesh/primitives/dim3/capsule.rs b/crates/bevy_render/src/mesh/primitives/dim3/capsule.rs index fc53d0256a..8efc1e199a 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/capsule.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/capsule.rs @@ -1,5 +1,5 @@ use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; use bevy_math::{primitives::Capsule3d, Vec2, Vec3}; @@ -91,9 +91,10 @@ impl Capsule3dMeshBuilder { self.uv_profile = uv_profile; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for Capsule3dMeshBuilder { + fn build(&self) -> Mesh { // code adapted from https://behreajj.medium.com/making-a-capsule-mesh-via-script-in-five-3d-environments-c2214abf02db let Capsule3dMeshBuilder { capsule, @@ -437,9 +438,3 @@ impl From for Mesh { capsule.mesh().build() } } - -impl From for Mesh { - fn from(capsule: Capsule3dMeshBuilder) -> Self { - capsule.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/dim3/cone.rs b/crates/bevy_render/src/mesh/primitives/dim3/cone.rs index 58b49af5ed..9d25bc00ec 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/cone.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/cone.rs @@ -2,7 +2,7 @@ use bevy_math::{primitives::Cone, Vec3}; use wgpu::PrimitiveTopology; use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; @@ -43,9 +43,10 @@ impl ConeMeshBuilder { self.resolution = resolution; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for ConeMeshBuilder { + fn build(&self) -> Mesh { let half_height = self.cone.height / 2.0; // `resolution` vertices for the base, `resolution` vertices for the bottom of the lateral surface, @@ -157,17 +158,11 @@ impl From for Mesh { } } -impl From for Mesh { - fn from(cone: ConeMeshBuilder) -> Self { - cone.build() - } -} - #[cfg(test)] mod tests { use bevy_math::{primitives::Cone, Vec2}; - use crate::mesh::{Mesh, Meshable, VertexAttributeValues}; + use crate::mesh::{primitives::MeshBuilder, Mesh, Meshable, VertexAttributeValues}; /// Rounds floats to handle floating point error in tests. fn round_floats(points: &mut [[f32; N]]) { diff --git a/crates/bevy_render/src/mesh/primitives/dim3/cylinder.rs b/crates/bevy_render/src/mesh/primitives/dim3/cylinder.rs index 64e3df24c6..ba7bf03d36 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/cylinder.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/cylinder.rs @@ -2,7 +2,7 @@ use bevy_math::primitives::Cylinder; use wgpu::PrimitiveTopology; use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; @@ -58,9 +58,10 @@ impl CylinderMeshBuilder { self.segments = segments; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for CylinderMeshBuilder { + fn build(&self) -> Mesh { let resolution = self.resolution; let segments = self.segments; @@ -176,9 +177,3 @@ impl From for Mesh { cylinder.mesh().build() } } - -impl From for Mesh { - fn from(cylinder: CylinderMeshBuilder) -> Self { - cylinder.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/dim3/plane.rs b/crates/bevy_render/src/mesh/primitives/dim3/plane.rs index 7012a48446..2ea9fad1e3 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/plane.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/plane.rs @@ -2,7 +2,7 @@ use bevy_math::{primitives::Plane3d, Dir3, Quat, Vec2, Vec3}; use wgpu::PrimitiveTopology; use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; @@ -65,9 +65,10 @@ impl PlaneMeshBuilder { self.plane.half_size = Vec2::new(width, height) / 2.0; self } +} - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for PlaneMeshBuilder { + fn build(&self) -> Mesh { let rotation = Quat::from_rotation_arc(Vec3::Y, *self.plane.normal); let positions = vec![ rotation * Vec3::new(self.plane.half_size.x, 0.0, -self.plane.half_size.y), @@ -104,9 +105,3 @@ impl From for Mesh { plane.mesh().build() } } - -impl From for Mesh { - fn from(plane: PlaneMeshBuilder) -> Self { - plane.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/dim3/sphere.rs b/crates/bevy_render/src/mesh/primitives/dim3/sphere.rs index 3c3c5755ad..fd6e7eed76 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/sphere.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/sphere.rs @@ -1,7 +1,7 @@ use std::f32::consts::PI; use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; use bevy_math::primitives::Sphere; @@ -75,19 +75,6 @@ impl SphereMeshBuilder { self } - /// Builds a [`Mesh`] according to the configuration in `self`. - /// - /// # Panics - /// - /// Panics if the sphere is a [`SphereKind::Ico`] with a subdivision count - /// that is greater than or equal to `80` because there will be too many vertices. - pub fn build(&self) -> Mesh { - match self.kind { - SphereKind::Ico { subdivisions } => self.ico(subdivisions).unwrap(), - SphereKind::Uv { sectors, stacks } => self.uv(sectors, stacks), - } - } - /// Creates an icosphere mesh with the given number of subdivisions. /// /// The number of faces quadruples with each subdivision. @@ -244,6 +231,21 @@ impl SphereMeshBuilder { } } +impl MeshBuilder for SphereMeshBuilder { + /// Builds a [`Mesh`] according to the configuration in `self`. + /// + /// # Panics + /// + /// Panics if the sphere is a [`SphereKind::Ico`] with a subdivision count + /// that is greater than or equal to `80` because there will be too many vertices. + fn build(&self) -> Mesh { + match self.kind { + SphereKind::Ico { subdivisions } => self.ico(subdivisions).unwrap(), + SphereKind::Uv { sectors, stacks } => self.uv(sectors, stacks), + } + } +} + impl Meshable for Sphere { type Output = SphereMeshBuilder; @@ -260,9 +262,3 @@ impl From for Mesh { sphere.mesh().build() } } - -impl From for Mesh { - fn from(sphere: SphereMeshBuilder) -> Self { - sphere.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/dim3/torus.rs b/crates/bevy_render/src/mesh/primitives/dim3/torus.rs index 479c686025..df3f6b7813 100644 --- a/crates/bevy_render/src/mesh/primitives/dim3/torus.rs +++ b/crates/bevy_render/src/mesh/primitives/dim3/torus.rs @@ -2,7 +2,7 @@ use bevy_math::{primitives::Torus, Vec3}; use wgpu::PrimitiveTopology; use crate::{ - mesh::{Indices, Mesh, Meshable}, + mesh::{Indices, Mesh, MeshBuilder, Meshable}, render_asset::RenderAssetUsages, }; @@ -65,9 +65,10 @@ impl TorusMeshBuilder { self.major_resolution = resolution; self } +} - /// Builds a [`Mesh`] according to the configuration in `self`. - pub fn build(&self) -> Mesh { +impl MeshBuilder for TorusMeshBuilder { + fn build(&self) -> Mesh { // code adapted from http://apparat-engine.blogspot.com/2013/04/procedural-meshes-torus.html let n_vertices = (self.major_resolution + 1) * (self.minor_resolution + 1); @@ -158,9 +159,3 @@ impl From for Mesh { torus.mesh().build() } } - -impl From for Mesh { - fn from(torus: TorusMeshBuilder) -> Self { - torus.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index a2bb01599b..48ede8e663 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -25,12 +25,26 @@ pub use dim2::{CircleMeshBuilder, EllipseMeshBuilder}; mod dim3; pub use dim3::*; +use super::Mesh; + /// A trait for shapes that can be turned into a [`Mesh`](super::Mesh). pub trait Meshable { /// The output of [`Self::mesh`]. This can either be a [`Mesh`](super::Mesh) - /// or a builder used for creating a [`Mesh`](super::Mesh). + /// or a [`MeshBuilder`] used for creating a [`Mesh`](super::Mesh). type Output; /// Creates a [`Mesh`](super::Mesh) for a shape. fn mesh(&self) -> Self::Output; } + +/// A trait used to build [`Mesh`]es from a configuration +pub trait MeshBuilder { + /// Builds a [`Mesh`] based on the configuration in `self`. + fn build(&self) -> Mesh; +} + +impl From for Mesh { + fn from(builder: T) -> Self { + builder.build() + } +}