From 758f250467a7b3675b696bbe0f0d3354a468fdea Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 11:38:42 +0200 Subject: [PATCH 01/19] Derive `Default` for some 2D primitives --- crates/bevy_math/src/primitives/dim2.rs | 63 ++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 993097087c8f4..452bfa2a36e9d 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -82,6 +82,12 @@ pub struct Circle { } impl Primitive2d for Circle {} +impl Default for Circle { + fn default() -> Self { + Self { radius: 0.5 } + } +} + /// An ellipse primitive #[derive(Clone, Copy, Debug)] pub struct Ellipse { @@ -92,6 +98,15 @@ pub struct Ellipse { } impl Primitive2d for Ellipse {} +impl Default for Ellipse { + fn default() -> Self { + Self { + half_width: 1.0, + half_height: 0.5, + } + } +} + impl Ellipse { /// Create a new `Ellipse` from a "width" and a "height" pub fn new(width: f32, height: f32) -> Self { @@ -111,6 +126,14 @@ pub struct Plane2d { } impl Primitive2d for Plane2d {} +impl Default for Plane2d { + fn default() -> Self { + Self { + normal: Direction2d::from_normalized(Vec2::Y), + } + } +} + impl Plane2d { /// Create a new `Plane2d` from a normal /// @@ -138,7 +161,7 @@ impl Primitive2d for Line2d {} /// A segment of a line along a direction in 2D space. #[doc(alias = "LineSegment2d")] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct Segment2d { /// The direction of the line segment pub direction: Direction2d, @@ -236,13 +259,21 @@ impl BoxedPolyline2d { } /// A triangle in 2D space -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Triangle2d { /// The vertices of the triangle pub vertices: [Vec2; 3], } impl Primitive2d for Triangle2d {} +impl Default for Triangle2d { + fn default() -> Self { + Self { + vertices: [Vec2::Y * 0.5, Vec2::new(-0.5, -0.5), Vec2::new(0.5, -0.5)], + } + } +} + impl Triangle2d { /// Create a new `Triangle2d` from points `a`, `b`, and `c` pub fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { @@ -283,6 +314,15 @@ pub struct Rectangle { } impl Primitive2d for Rectangle {} +impl Default for Rectangle { + fn default() -> Self { + Self { + half_width: 0.5, + half_height: 0.5, + } + } +} + impl Rectangle { /// Create a rectangle from a full width and height pub fn new(width: f32, height: f32) -> Self { @@ -363,18 +403,27 @@ pub struct RegularPolygon { } impl Primitive2d for RegularPolygon {} +impl Default for RegularPolygon { + fn default() -> Self { + Self { + circumcircle: Circle { radius: 0.5 }, + sides: 6, + } + } +} + impl RegularPolygon { /// Create a new `RegularPolygon` - /// from the radius of the circumcircle and number of sides + /// from the radius of the circumcircle and a number of sides /// /// # Panics /// - /// Panics if `circumcircle_radius` is non-positive - pub fn new(circumcircle_radius: f32, sides: usize) -> Self { - assert!(circumcircle_radius > 0.0); + /// Panics if `circumradius` is non-positive + pub fn new(circumradius: f32, sides: usize) -> Self { + assert!(circumradius > 0.0); Self { circumcircle: Circle { - radius: circumcircle_radius, + radius: circumradius, }, sides, } From 7018094fec73d07f7f9a58f5ac527574712f38c6 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 12:21:11 +0200 Subject: [PATCH 02/19] Add `Meshable`, `Facing`, and mesh builders for 2D primitives --- crates/bevy_math/src/primitives/dim2.rs | 2 +- crates/bevy_render/src/mesh/mod.rs | 2 + .../bevy_render/src/mesh/primitives/circle.rs | 87 ++++++++++ .../src/mesh/primitives/ellipse.rs | 156 ++++++++++++++++++ crates/bevy_render/src/mesh/primitives/mod.rs | 119 +++++++++++++ .../src/mesh/primitives/rectangle.rs | 100 +++++++++++ .../src/mesh/primitives/regular_polygon.rs | 72 ++++++++ .../src/mesh/primitives/triangle.rs | 99 +++++++++++ 8 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_render/src/mesh/primitives/circle.rs create mode 100644 crates/bevy_render/src/mesh/primitives/ellipse.rs create mode 100644 crates/bevy_render/src/mesh/primitives/mod.rs create mode 100644 crates/bevy_render/src/mesh/primitives/rectangle.rs create mode 100644 crates/bevy_render/src/mesh/primitives/regular_polygon.rs create mode 100644 crates/bevy_render/src/mesh/primitives/triangle.rs diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 452bfa2a36e9d..92d2051b48148 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -276,7 +276,7 @@ impl Default for Triangle2d { impl Triangle2d { /// Create a new `Triangle2d` from points `a`, `b`, and `c` - pub fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { + pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { Self { vertices: [a, b, c], } diff --git a/crates/bevy_render/src/mesh/mod.rs b/crates/bevy_render/src/mesh/mod.rs index 39c9b19cc9e5b..0a070d0388b24 100644 --- a/crates/bevy_render/src/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mod.rs @@ -1,10 +1,12 @@ #[allow(clippy::module_inception)] mod mesh; pub mod morph; +pub mod primitives; /// Generation for some primitive shape meshes. pub mod shape; pub use mesh::*; +pub use primitives::*; use crate::{prelude::Image, render_asset::RenderAssetPlugin}; use bevy_app::{App, Plugin}; diff --git a/crates/bevy_render/src/mesh/primitives/circle.rs b/crates/bevy_render/src/mesh/primitives/circle.rs new file mode 100644 index 0000000000000..67b1c432085c9 --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/circle.rs @@ -0,0 +1,87 @@ +use crate::mesh::Mesh; + +use super::{Facing, MeshFacingExtension, Meshable}; +use bevy_math::primitives::{Circle, RegularPolygon}; + +/// A builder used for creating a [`Mesh`] with a [`Circle`] shape. +#[derive(Clone, Copy, Debug)] +pub struct CircleMeshBuilder { + /// The [`Circle`] shape. + pub circle: Circle, + /// The number of vertices used for the circle mesh. + /// The default is `32`. + #[doc(alias = "vertices")] + pub resolution: usize, + /// The XYZ direction that the mesh is facing. + /// The default is [`Facing::Z`]. + pub facing: Facing, +} + +impl Default for CircleMeshBuilder { + fn default() -> Self { + Self { + circle: Circle::default(), + resolution: 32, + facing: Facing::Z, + } + } +} + +impl MeshFacingExtension for CircleMeshBuilder { + #[inline] + fn facing(mut self, facing: Facing) -> Self { + self.facing = facing; + self + } +} + +impl CircleMeshBuilder { + /// Creates a new [`CircleMesh`] from a given radius and vertex count. + #[inline] + pub const fn new(radius: f32, resolution: usize) -> Self { + Self { + circle: Circle { radius }, + resolution, + facing: Facing::Z, + } + } + + /// Sets the number of resolution used for the circle mesh. + #[inline] + #[doc(alias = "vertices")] + pub const fn resolution(mut self, resolution: usize) -> Self { + self.resolution = resolution; + self + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + RegularPolygon::new(self.circle.radius, self.resolution) + .mesh() + .facing(self.facing) + .build() + } +} + +impl Meshable for Circle { + type Output = CircleMeshBuilder; + + fn mesh(&self) -> Self::Output { + CircleMeshBuilder { + circle: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(circle: Circle) -> Self { + circle.mesh().build() + } +} + +impl From for Mesh { + fn from(circle: CircleMeshBuilder) -> Self { + circle.build() + } +} diff --git a/crates/bevy_render/src/mesh/primitives/ellipse.rs b/crates/bevy_render/src/mesh/primitives/ellipse.rs new file mode 100644 index 0000000000000..ee08fc8cc2546 --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/ellipse.rs @@ -0,0 +1,156 @@ +use crate::{ + mesh::{Indices, Mesh}, + render_asset::RenderAssetPersistencePolicy, +}; + +use super::{Facing, MeshFacingExtension, Meshable}; +use bevy_math::{primitives::Ellipse, Vec3}; +use wgpu::PrimitiveTopology; + +/// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. +#[derive(Clone, Copy, Debug)] +pub struct EllipseMeshBuilder { + /// The [`Ellipse`] shape. + pub ellipse: Ellipse, + /// The number of vertices used for the ellipse mesh. + /// The default is `32`. + #[doc(alias = "vertices")] + pub resolution: usize, + /// The XYZ direction that the mesh is facing. + /// The default is [`Facing::Z`]. + pub facing: Facing, +} + +impl Default for EllipseMeshBuilder { + fn default() -> Self { + Self { + ellipse: Ellipse::default(), + resolution: 32, + facing: Facing::Z, + } + } +} + +impl MeshFacingExtension for EllipseMeshBuilder { + #[inline] + fn facing(mut self, facing: Facing) -> Self { + self.facing = facing; + self + } +} + +impl EllipseMeshBuilder { + /// Creates a new [`EllipseMesh`] from a given half width and half height and a vertex count. + #[inline] + pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { + Self { + ellipse: Ellipse { + half_width, + half_height, + }, + resolution, + facing: Facing::Z, + } + } + + /// Sets the number of vertices used for the ellipse mesh. + #[inline] + #[doc(alias = "vertices")] + pub const fn resolution(mut self, resolution: usize) -> Self { + self.resolution = resolution; + self + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + let mut indices = Vec::with_capacity((self.resolution - 2) * 3); + let mut positions = Vec::with_capacity(self.resolution); + let mut normals = Vec::with_capacity(self.resolution); + let mut uvs = Vec::with_capacity(self.resolution); + + self.build_mesh_data( + Vec3::ZERO, + &mut indices, + &mut positions, + &mut normals, + &mut uvs, + ); + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_indices(Some(Indices::U32(indices))) + } + + /// Builds the ellipse mesh and pushes the data to the given vertex attribute data sets. + pub(super) fn build_mesh_data( + &self, + translation: Vec3, + indices: &mut Vec, + positions: &mut Vec<[f32; 3]>, + normals: &mut Vec<[f32; 3]>, + uvs: &mut Vec<[f32; 2]>, + ) { + let sides = self.resolution; + let facing_coords = self.facing.to_array(); + let normal_sign = self.facing.signum() as f32; + + // The mesh could have existing vertices, so we add an offset to find + // the index where the ellipse's own vertices begin. + let index_offset = positions.len() as u32; + + // Add pi/2 so that there is a vertex at the top (sin is 1.0 and cos is 0.0) + let start_angle = std::f32::consts::FRAC_PI_2; + let step = normal_sign * std::f32::consts::TAU / sides as f32; + + for i in 0..sides { + // Compute vertex position at angle theta + let theta = start_angle + i as f32 * step; + let (sin, cos) = theta.sin_cos(); + let x = cos * self.ellipse.half_width; + let y = sin * self.ellipse.half_height; + + // Transform vertex position based on facing direction + let position = match self.facing { + Facing::X | Facing::NegX => Vec3::new(0.0, y, -x), + Facing::Y | Facing::NegY => Vec3::new(x, 0.0, -y), + Facing::Z | Facing::NegZ => Vec3::new(x, y, 0.0), + }; + + positions.push((position + translation).to_array()); + normals.push(facing_coords); + uvs.push([0.5 * (cos + 1.0), 1.0 - 0.5 * (sin + 1.0)]); + } + + for i in 1..(sides as u32 - 1) { + indices.extend_from_slice(&[index_offset, index_offset + i, index_offset + i + 1]); + } + } +} + +impl Meshable for Ellipse { + type Output = EllipseMeshBuilder; + + fn mesh(&self) -> Self::Output { + EllipseMeshBuilder { + ellipse: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(ellipse: Ellipse) -> Self { + ellipse.mesh().build() + } +} + +impl From for Mesh { + fn from(ellipse: EllipseMeshBuilder) -> Self { + ellipse.build() + } +} diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs new file mode 100644 index 0000000000000..640c4e5f242cd --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -0,0 +1,119 @@ +//! Mesh generation for [primitive shapes](bevy_math::primitives). + +#![warn(missing_docs)] + +mod circle; +mod ellipse; +mod rectangle; +mod regular_polygon; +mod triangle; + +pub use circle::CircleMeshBuilder; +pub use ellipse::EllipseMeshBuilder; +pub use rectangle::RectangleMeshBuilder; +pub use regular_polygon::RegularPolygonMeshBuilder; +pub use triangle::Triangle2dMeshBuilder; + +use super::Mesh; + +/// A trait for shapes that can be turned into a [`Mesh`]. +pub trait Meshable { + /// The output of [`Self::mesh`]. This can either be a [`Mesh`] + /// or a builder used for creating a [`Mesh`]. + type Output; + + /// Creates a [`Mesh`] for a shape. + fn mesh(&self) -> Self::Output; +} + +/// The cartesian axis that a [`Mesh`] should be facing upon creation. +/// This is either positive or negative `X`, `Y`, or `Z`. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub enum Facing { + /// Facing the `+X` direction. + X = 1, + /// Facing the `+Y` direction. + Y = 2, + /// Facing the `+Z` direction. + #[default] + Z = 3, + /// Facing the `-X` direction. + NegX = -1, + /// Facing the `-Y` direction. + NegY = -2, + /// Facing the `-Z` direction. + NegZ = -3, +} + +impl Facing { + /// Returns `1` if the facing direction is positive `X`, `Y`, or `Z`, and `-1` otherwise. + #[inline] + pub const fn signum(&self) -> i8 { + match self { + Facing::X | Facing::Y | Facing::Z => 1, + _ => -1, + } + } + + /// Returns the direction as an array in the format `[x, y, z]`. + /// + /// # Example + /// + /// ``` + /// # use bevy_render::prelude::Facing; + /// assert_eq!(Facing::X.to_array(), [1.0, 0.0, 0.0]); + /// ``` + #[inline] + pub const fn to_array(&self) -> [f32; 3] { + match self { + Facing::X => [1.0, 0.0, 0.0], + Facing::Y => [0.0, 1.0, 0.0], + Facing::Z => [0.0, 0.0, 1.0], + Facing::NegX => [-1.0, 0.0, 0.0], + Facing::NegY => [0.0, -1.0, 0.0], + Facing::NegZ => [0.0, 0.0, -1.0], + } + } +} + +/// An extension trait for methods related to setting a specific [`Facing`] direction. +pub trait MeshFacingExtension: Sized { + /// Set the [`Facing`] direction. + fn facing(self, facing: Facing) -> Self; + + /// Set the [`Facing`] direction to `+X`. + #[inline] + fn facing_x(self) -> Self { + self.facing(Facing::X) + } + + /// Set the [`Facing`] direction to `+Y`. + #[inline] + fn facing_y(self) -> Self { + self.facing(Facing::Y) + } + + /// Set the [`Facing`] direction to `+Z`. + #[inline] + fn facing_z(self) -> Self { + self.facing(Facing::Z) + } + + /// Set the [`Facing`] direction to `-X`. + #[inline] + fn facing_neg_x(self) -> Self { + self.facing(Facing::NegX) + } + + /// Set the [`Facing`] direction to `-Y`. + #[inline] + fn facing_neg_y(self) -> Self { + self.facing(Facing::NegY) + } + + /// Set the [`Facing`] direction to `-Z`. + #[inline] + fn facing_neg_z(self) -> Self { + self.facing(Facing::NegZ) + } +} diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs new file mode 100644 index 0000000000000..eb74feadeb233 --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/rectangle.rs @@ -0,0 +1,100 @@ +use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; +use bevy_math::primitives::Rectangle; +use wgpu::PrimitiveTopology; + +/// A builder used for creating a [`Mesh`] with a [`Rectangle`] shape. +#[derive(Clone, Copy, Debug, Default)] +pub struct RectangleMeshBuilder { + /// The [`Rectangle`] shape. + pub rectangle: Rectangle, + /// The XYZ direction that the mesh is facing. + /// The default is [`Facing::Z`]. + pub facing: Facing, +} + +impl MeshFacingExtension for RectangleMeshBuilder { + #[inline] + fn facing(mut self, facing: Facing) -> Self { + self.facing = facing; + self + } +} + +impl RectangleMeshBuilder { + /// Creates a new [`RectangleMesh`] from a given radius and vertex count. + #[inline] + pub fn new(width: f32, height: f32) -> Self { + Self { + rectangle: Rectangle::new(width, height), + facing: Facing::Z, + } + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + let [hw, hh] = [self.rectangle.half_width, self.rectangle.half_height]; + let positions = match self.facing { + Facing::Z | Facing::NegZ => vec![ + [hw, hh, 0.0], + [-hw, hh, 0.0], + [-hw, -hh, 0.0], + [hw, -hh, 0.0], + ], + Facing::Y | Facing::NegY => vec![ + [hw, 0.0, -hh], + [-hw, 0.0, -hh], + [-hw, 0.0, hh], + [hw, 0.0, hh], + ], + Facing::X | Facing::NegX => vec![ + [0.0, hh, -hw], + [0.0, hh, hw], + [0.0, -hh, hw], + [0.0, -hh, -hw], + ], + }; + + let normals = vec![self.facing.to_array(); 4]; + let uvs = vec![[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]]; + + // Flip indices if facing -X, -Y, or -Z + let indices = if self.facing.signum() > 0 { + Indices::U32(vec![0, 1, 2, 0, 2, 3]) + } else { + Indices::U32(vec![0, 2, 1, 0, 3, 2]) + }; + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + } +} + +impl Meshable for Rectangle { + type Output = RectangleMeshBuilder; + + fn mesh(&self) -> Self::Output { + RectangleMeshBuilder { + rectangle: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(rectangle: Rectangle) -> Self { + rectangle.mesh().build() + } +} + +impl From for Mesh { + fn from(rectangle: RectangleMeshBuilder) -> Self { + rectangle.build() + } +} diff --git a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs new file mode 100644 index 0000000000000..f0d541b30bedc --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs @@ -0,0 +1,72 @@ +use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use bevy_math::primitives::{Ellipse, RegularPolygon}; + +/// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape. +#[derive(Clone, Copy, Debug, Default)] +pub struct RegularPolygonMeshBuilder { + /// The [`RegularPolygon`] shape. + pub polygon: RegularPolygon, + /// The XYZ direction that the mesh is facing. + /// The default is [`Facing::Z`]. + pub facing: Facing, +} + +impl MeshFacingExtension for RegularPolygonMeshBuilder { + #[inline] + fn facing(mut self, facing: Facing) -> Self { + self.facing = facing; + self + } +} + +impl RegularPolygonMeshBuilder { + /// Creates a new [`RegularPolygonMesh`] from the radius + /// of the circumcircle and a number of sides. + /// + /// # Panics + /// + /// Panics if `circumradius` is non-positive. + #[inline] + pub fn new(circumradius: f32, sides: usize) -> Self { + Self { + polygon: RegularPolygon::new(circumradius, sides), + ..Default::default() + } + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + // The ellipse mesh is just a regular polygon with two radii + Ellipse { + half_width: self.polygon.circumcircle.radius, + half_height: self.polygon.circumcircle.radius, + } + .mesh() + .resolution(self.polygon.sides) + .facing(self.facing) + .build() + } +} + +impl Meshable for RegularPolygon { + type Output = RegularPolygonMeshBuilder; + + fn mesh(&self) -> Self::Output { + RegularPolygonMeshBuilder { + polygon: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(polygon: RegularPolygon) -> Self { + polygon.mesh().build() + } +} + +impl From for Mesh { + fn from(polygon: RegularPolygonMeshBuilder) -> Self { + polygon.build() + } +} diff --git a/crates/bevy_render/src/mesh/primitives/triangle.rs b/crates/bevy_render/src/mesh/primitives/triangle.rs new file mode 100644 index 0000000000000..983ff81765fbc --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/triangle.rs @@ -0,0 +1,99 @@ +use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; +use bevy_math::{ + primitives::{Triangle2d, WindingOrder}, + Vec2, +}; +use wgpu::PrimitiveTopology; + +/// A builder used for creating a [`Mesh`] with a [`Triangle2d`] shape. +#[derive(Clone, Copy, Debug, Default)] +pub struct Triangle2dMeshBuilder { + /// The [`Triangle2d`] shape. + pub triangle: Triangle2d, + /// The XYZ direction that the mesh is facing. + /// The default is [`Facing::Z`]. + pub facing: Facing, +} + +impl MeshFacingExtension for Triangle2dMeshBuilder { + #[inline] + fn facing(mut self, facing: Facing) -> Self { + self.facing = facing; + self + } +} + +impl Triangle2dMeshBuilder { + /// Creates a new [`Triangle2dMesh`] from points `a`, `b`, and `c`. + #[inline] + pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { + Self { + triangle: Triangle2d::new(a, b, c), + facing: Facing::Z, + } + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + let [a, b, c] = self.triangle.vertices; + + let positions = match self.facing { + Facing::X | Facing::NegX => [[0.0, a.y, -a.x], [0.0, b.y, -b.x], [0.0, c.y, -c.x]], + Facing::Y | Facing::NegY => [[a.x, 0.0, -a.y], [b.x, 0.0, -b.y], [c.x, 0.0, -c.y]], + Facing::Z | Facing::NegZ => [[a.x, a.y, 0.0], [b.x, b.y, 0.0], [c.x, c.y, 0.0]], + }; + + let normals = vec![self.facing.to_array(); 3]; + + // The extents of the bounding box of the triangle, + // used to compute the UV coordinates of the points. + let extents = a.min(b).min(c).abs().max(a.max(b).max(c)) * Vec2::new(1.0, -1.0); + let uvs = vec![ + a / extents / 2.0 + 0.5, + b / extents / 2.0 + 0.5, + c / extents / 2.0 + 0.5, + ]; + + let flipped = self.facing.signum() < 0; + let is_ccw = self.triangle.winding_order() == WindingOrder::CounterClockwise; + let is_cw = self.triangle.winding_order() == WindingOrder::Clockwise; + let indices = if (is_ccw && !flipped) || (is_cw && flipped) { + Indices::U32(vec![0, 1, 2]) + } else { + Indices::U32(vec![0, 2, 1]) + }; + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, Vec::from(positions)) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + } +} + +impl Meshable for Triangle2d { + type Output = Triangle2dMeshBuilder; + + fn mesh(&self) -> Triangle2dMeshBuilder { + Triangle2dMeshBuilder { + triangle: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(triangle: Triangle2d) -> Self { + triangle.mesh().build() + } +} + +impl From for Mesh { + fn from(triangle: Triangle2dMeshBuilder) -> Self { + triangle.build() + } +} From 6f53e165e69f325e6fccf7c53ff1adeb8071cb69 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 12:37:44 +0200 Subject: [PATCH 03/19] Use primitives in `2d_shapes` example and tweak colors --- Cargo.toml | 2 +- examples/2d/2d_shapes.rs | 45 +++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9860169f2250d..8cad37e80af1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -396,7 +396,7 @@ doc-scrape-examples = true [package.metadata.example.2d_shapes] name = "2D Shapes" -description = "Renders a rectangle, circle, and hexagon" +description = "Renders simple 2D primitive shapes" category = "2D Rendering" wasm = true diff --git a/examples/2d/2d_shapes.rs b/examples/2d/2d_shapes.rs index 9a16f96ce5a50..b3bce026f60dd 100644 --- a/examples/2d/2d_shapes.rs +++ b/examples/2d/2d_shapes.rs @@ -18,36 +18,47 @@ fn setup( // Circle commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(shape::Circle::new(50.)).into(), - material: materials.add(Color::PURPLE), - transform: Transform::from_translation(Vec3::new(-150., 0., 0.)), + mesh: meshes.add(primitives::Circle { radius: 50.0 }).into(), + material: materials.add(Color::VIOLET), + transform: Transform::from_translation(Vec3::new(-225.0, 0.0, 0.0)), ..default() }); - // Rectangle - commands.spawn(SpriteBundle { - sprite: Sprite { - color: Color::rgb(0.25, 0.25, 0.75), - custom_size: Some(Vec2::new(50.0, 100.0)), - ..default() - }, - transform: Transform::from_translation(Vec3::new(-50., 0., 0.)), + // Ellipse + commands.spawn(MaterialMesh2dBundle { + mesh: meshes.add(primitives::Ellipse::new(50.0, 100.0)).into(), + material: materials.add(Color::TURQUOISE), + transform: Transform::from_translation(Vec3::new(-100.0, 0.0, 0.0)), ..default() }); - // Quad + // Rectangle commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(shape::Quad::new(Vec2::new(50., 100.))).into(), + mesh: meshes.add(primitives::Rectangle::new(50.0, 100.0)).into(), material: materials.add(Color::LIME_GREEN), - transform: Transform::from_translation(Vec3::new(50., 0., 0.)), + transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)), ..default() }); // Hexagon commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(shape::RegularPolygon::new(50., 6)).into(), - material: materials.add(Color::TURQUOISE), - transform: Transform::from_translation(Vec3::new(150., 0., 0.)), + mesh: meshes.add(primitives::RegularPolygon::new(50.0, 6)).into(), + material: materials.add(Color::YELLOW), + transform: Transform::from_translation(Vec3::new(125.0, 0.0, 0.0)), + ..default() + }); + + // Triangle + commands.spawn(MaterialMesh2dBundle { + mesh: meshes + .add(primitives::Triangle2d::new( + Vec2::Y * 50.0, + Vec2::new(-50.0, -50.0), + Vec2::new(50.0, -50.0), + )) + .into(), + material: materials.add(Color::ORANGE), + transform: Transform::from_translation(Vec3::new(250.0, 0.0, 0.0)), ..default() }); } From b4865eccf5616cb6664fca095294a577775842cc Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 13:17:23 +0200 Subject: [PATCH 04/19] Fix doc comments --- crates/bevy_render/src/mesh/primitives/circle.rs | 2 +- crates/bevy_render/src/mesh/primitives/rectangle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/circle.rs b/crates/bevy_render/src/mesh/primitives/circle.rs index 67b1c432085c9..b73240e0ebd63 100644 --- a/crates/bevy_render/src/mesh/primitives/circle.rs +++ b/crates/bevy_render/src/mesh/primitives/circle.rs @@ -46,7 +46,7 @@ impl CircleMeshBuilder { } } - /// Sets the number of resolution used for the circle mesh. + /// Sets the number of vertices used for the circle mesh. #[inline] #[doc(alias = "vertices")] pub const fn resolution(mut self, resolution: usize) -> Self { diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs index eb74feadeb233..33d04ce9b96e5 100644 --- a/crates/bevy_render/src/mesh/primitives/rectangle.rs +++ b/crates/bevy_render/src/mesh/primitives/rectangle.rs @@ -22,7 +22,7 @@ impl MeshFacingExtension for RectangleMeshBuilder { } impl RectangleMeshBuilder { - /// Creates a new [`RectangleMesh`] from a given radius and vertex count. + /// Creates a new [`RectangleMesh`] from a given `width` and `height`. #[inline] pub fn new(width: f32, height: f32) -> Self { Self { From df0e2e925b43ee5defcb1c5a7c30b18bf20a1400 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 13:23:07 +0200 Subject: [PATCH 05/19] Update examples README.md --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index e03d0a0db27d2..230087858ea33 100644 --- a/examples/README.md +++ b/examples/README.md @@ -95,7 +95,7 @@ Example | Description [2D Bloom](../examples/2d/bloom_2d.rs) | Illustrates bloom post-processing in 2d [2D Gizmos](../examples/2d/2d_gizmos.rs) | A scene showcasing 2D gizmos [2D Rotation](../examples/2d/rotation.rs) | Demonstrates rotating entities in 2D with quaternions -[2D Shapes](../examples/2d/2d_shapes.rs) | Renders a rectangle, circle, and hexagon +[2D Shapes](../examples/2d/2d_shapes.rs) | Renders simple 2D primitive shapes [2D Viewport To World](../examples/2d/2d_viewport_to_world.rs) | Demonstrates how to use the `Camera::viewport_to_world_2d` method [Custom glTF vertex attribute 2D](../examples/2d/custom_gltf_vertex_attribute.rs) | Renders a glTF mesh in 2D with a custom vertex attribute [Manual Mesh 2D](../examples/2d/mesh2d_manual.rs) | Renders a custom mesh "manually" with "mid-level" renderer apis From c315937207c3f5fe1d00ab3980eac1ec30196397 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 13:29:37 +0200 Subject: [PATCH 06/19] Add facing in `bevy_render::prelude` --- crates/bevy_render/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 5014b948537bc..4da6c2e09ce01 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -34,7 +34,11 @@ pub mod prelude { Projection, }, color::Color, - mesh::{morph::MorphWeights, shape, Mesh}, + mesh::{ + morph::MorphWeights, + primitives::{Facing, MeshFacingExtension}, + shape, Mesh, + }, render_resource::Shader, spatial_bundle::SpatialBundle, texture::{Image, ImagePlugin}, From 38e25a7e7c4e986351d1ff30588846d77fa38513 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 13:44:12 +0200 Subject: [PATCH 07/19] Fix doc links --- crates/bevy_render/src/mesh/primitives/circle.rs | 2 +- crates/bevy_render/src/mesh/primitives/ellipse.rs | 2 +- crates/bevy_render/src/mesh/primitives/rectangle.rs | 2 +- crates/bevy_render/src/mesh/primitives/regular_polygon.rs | 2 +- crates/bevy_render/src/mesh/primitives/triangle.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/circle.rs b/crates/bevy_render/src/mesh/primitives/circle.rs index b73240e0ebd63..c194067338889 100644 --- a/crates/bevy_render/src/mesh/primitives/circle.rs +++ b/crates/bevy_render/src/mesh/primitives/circle.rs @@ -36,7 +36,7 @@ impl MeshFacingExtension for CircleMeshBuilder { } impl CircleMeshBuilder { - /// Creates a new [`CircleMesh`] from a given radius and vertex count. + /// Creates a new [`CircleMeshBuilder`] from a given radius and vertex count. #[inline] pub const fn new(radius: f32, resolution: usize) -> Self { Self { diff --git a/crates/bevy_render/src/mesh/primitives/ellipse.rs b/crates/bevy_render/src/mesh/primitives/ellipse.rs index ee08fc8cc2546..50978723b8fe0 100644 --- a/crates/bevy_render/src/mesh/primitives/ellipse.rs +++ b/crates/bevy_render/src/mesh/primitives/ellipse.rs @@ -40,7 +40,7 @@ impl MeshFacingExtension for EllipseMeshBuilder { } impl EllipseMeshBuilder { - /// Creates a new [`EllipseMesh`] from a given half width and half height and a vertex count. + /// Creates a new [`EllipseMeshBuilder`] from a given half width and half height and a vertex count. #[inline] pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { Self { diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs index 33d04ce9b96e5..5c10e982ce659 100644 --- a/crates/bevy_render/src/mesh/primitives/rectangle.rs +++ b/crates/bevy_render/src/mesh/primitives/rectangle.rs @@ -22,7 +22,7 @@ impl MeshFacingExtension for RectangleMeshBuilder { } impl RectangleMeshBuilder { - /// Creates a new [`RectangleMesh`] from a given `width` and `height`. + /// Creates a new [`RectangleMeshBuilder`] from a given `width` and `height`. #[inline] pub fn new(width: f32, height: f32) -> Self { Self { diff --git a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs index f0d541b30bedc..0f0fdd983484b 100644 --- a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs +++ b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs @@ -20,7 +20,7 @@ impl MeshFacingExtension for RegularPolygonMeshBuilder { } impl RegularPolygonMeshBuilder { - /// Creates a new [`RegularPolygonMesh`] from the radius + /// Creates a new [`RegularPolygonMeshBuilder`] from the radius /// of the circumcircle and a number of sides. /// /// # Panics diff --git a/crates/bevy_render/src/mesh/primitives/triangle.rs b/crates/bevy_render/src/mesh/primitives/triangle.rs index 983ff81765fbc..699b09985d824 100644 --- a/crates/bevy_render/src/mesh/primitives/triangle.rs +++ b/crates/bevy_render/src/mesh/primitives/triangle.rs @@ -25,7 +25,7 @@ impl MeshFacingExtension for Triangle2dMeshBuilder { } impl Triangle2dMeshBuilder { - /// Creates a new [`Triangle2dMesh`] from points `a`, `b`, and `c`. + /// Creates a new [`Triangle2dMeshBuilder`] from points `a`, `b`, and `c`. #[inline] pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { Self { From 41f3009f7fa6747f517e89fecf122145ead5337c Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 14:07:51 +0200 Subject: [PATCH 08/19] Add `Meshable` to `bevy_render::prelude` --- crates/bevy_render/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 4da6c2e09ce01..ede32fbfa5e72 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -36,7 +36,7 @@ pub mod prelude { color::Color, mesh::{ morph::MorphWeights, - primitives::{Facing, MeshFacingExtension}, + primitives::{Facing, MeshFacingExtension, Meshable}, shape, Mesh, }, render_resource::Shader, From ad690e54faf1693dde6100991ed6a5b89f23a67b Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 14:08:30 +0200 Subject: [PATCH 09/19] Improve module-level docs for primitive meshing --- crates/bevy_render/src/mesh/primitives/mod.rs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 640c4e5f242cd..92c573c1f497d 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -1,4 +1,37 @@ //! Mesh generation for [primitive shapes](bevy_math::primitives). +//! +//! Primitives that support meshing implement the [`Meshable`] trait. +//! Calling [`mesh`](Meshable::mesh) will return a builder that can be used +//! to specify shape-specific configuration. +//! +//! ``` +//! # use bevy_asset::Assets; +//! # use bevy_ecs::prelude::ResMut; +//! # use bevy_math::primitives; +//! # use bevy_render::prelude::*; +//! # +//! # fn setup(mut meshes: ResMut>) { +//! // Create circle mesh with default configuration +//! let circle = meshes.add(primitives::Circle { radius: 25.0 }); +//! +//! // Specify number of vertices +//! let circle = meshes.add(primitives::Circle { radius: 25.0 }.mesh().resolution(64)); +//! # } +//! ``` +//! +//! Some shapes also support different facing directions through the [`Facing`] enum or builder methods. +//! +//! ``` +//! # use bevy_asset::Assets; +//! # use bevy_ecs::prelude::ResMut; +//! # use bevy_math::primitives; +//! # use bevy_render::prelude::*; +//! # +//! # fn setup(mut meshes: ResMut>) { +//! // Create rectangle mesh facing up +//! let rectangle = meshes.add(primitives::Rectangle::new(50.0, 25.0).mesh().facing_y()); +//! # } +//! ``` #![warn(missing_docs)] From 381740889e2df2babb70340d00783b396524e211 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 18:04:52 +0200 Subject: [PATCH 10/19] Document default values for 2D primitives --- crates/bevy_math/src/primitives/dim2.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index d418362167d80..8f9ceb5e69134 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -83,6 +83,7 @@ pub struct Circle { impl Primitive2d for Circle {} impl Default for Circle { + /// Returns the default [`Circle`] with a radius of `0.5`. fn default() -> Self { Self { radius: 0.5 } } @@ -99,6 +100,7 @@ pub struct Ellipse { impl Primitive2d for Ellipse {} impl Default for Ellipse { + /// Returns the default [`Ellipse`] with a half-width of `1.0` and a half-height of `0.5`. fn default() -> Self { Self { half_width: 1.0, @@ -127,9 +129,10 @@ pub struct Plane2d { impl Primitive2d for Plane2d {} impl Default for Plane2d { + /// Returns the default [`Plane2d`] with a normal pointing in the `+Y` direction. fn default() -> Self { Self { - normal: Direction2d::from_normalized(Vec2::Y), + normal: Direction2d::Y, } } } @@ -267,6 +270,7 @@ pub struct Triangle2d { impl Primitive2d for Triangle2d {} impl Default for Triangle2d { + /// Returns the default [`Triangle2d`] with the vertices `[0.0, 0.5]`, `[-0.5, -0.5]`, and `[0.5, -0.5]`. fn default() -> Self { Self { vertices: [Vec2::Y * 0.5, Vec2::new(-0.5, -0.5), Vec2::new(0.5, -0.5)], @@ -350,6 +354,7 @@ pub struct Rectangle { impl Primitive2d for Rectangle {} impl Default for Rectangle { + /// Returns the default [`Rectangle`] with a half-width and half-height of `0.5`. fn default() -> Self { Self { half_width: 0.5, @@ -439,6 +444,7 @@ pub struct RegularPolygon { impl Primitive2d for RegularPolygon {} impl Default for RegularPolygon { + /// Returns the default [`RegularPolygon`] with six sides (a hexagon) and a circumradius of `0.5`. fn default() -> Self { Self { circumcircle: Circle { radius: 0.5 }, From 51ca697ddb00a4a9d0d8af70fa3987bfd45f6ca0 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 18:08:31 +0200 Subject: [PATCH 11/19] Improve `2d_shapes` example description Co-authored-by: Alice Cecile --- Cargo.toml | 2 +- examples/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8cad37e80af1c..6a682a014aa58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -396,7 +396,7 @@ doc-scrape-examples = true [package.metadata.example.2d_shapes] name = "2D Shapes" -description = "Renders simple 2D primitive shapes" +description = "Renders simple 2D primitive shapes like circles and polygons" category = "2D Rendering" wasm = true diff --git a/examples/README.md b/examples/README.md index 230087858ea33..f7d3555463086 100644 --- a/examples/README.md +++ b/examples/README.md @@ -95,7 +95,7 @@ Example | Description [2D Bloom](../examples/2d/bloom_2d.rs) | Illustrates bloom post-processing in 2d [2D Gizmos](../examples/2d/2d_gizmos.rs) | A scene showcasing 2D gizmos [2D Rotation](../examples/2d/rotation.rs) | Demonstrates rotating entities in 2D with quaternions -[2D Shapes](../examples/2d/2d_shapes.rs) | Renders simple 2D primitive shapes +[2D Shapes](../examples/2d/2d_shapes.rs) | Renders simple 2D primitive shapes like circles and polygons [2D Viewport To World](../examples/2d/2d_viewport_to_world.rs) | Demonstrates how to use the `Camera::viewport_to_world_2d` method [Custom glTF vertex attribute 2D](../examples/2d/custom_gltf_vertex_attribute.rs) | Renders a glTF mesh in 2D with a custom vertex attribute [Manual Mesh 2D](../examples/2d/mesh2d_manual.rs) | Renders a custom mesh "manually" with "mid-level" renderer apis From f6705a11cb2ebd7114451b1a96cf9434c605c058 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sat, 20 Jan 2024 20:33:34 +0200 Subject: [PATCH 12/19] Fix merge conflicts --- crates/bevy_math/src/primitives/dim2.rs | 6 ++---- crates/bevy_render/src/mesh/primitives/ellipse.rs | 9 ++++----- crates/bevy_render/src/mesh/primitives/rectangle.rs | 2 +- .../bevy_render/src/mesh/primitives/regular_polygon.rs | 8 +++++--- examples/2d/2d_shapes.rs | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 50e78162a3da8..3b5bdd846381b 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -103,8 +103,7 @@ impl Default for Ellipse { /// Returns the default [`Ellipse`] with a half-width of `1.0` and a half-height of `0.5`. fn default() -> Self { Self { - half_width: 1.0, - half_height: 0.5, + half_size: Vec2::new(1.0, 0.5), } } } @@ -378,8 +377,7 @@ impl Default for Rectangle { /// Returns the default [`Rectangle`] with a half-width and half-height of `0.5`. fn default() -> Self { Self { - half_width: 0.5, - half_height: 0.5, + half_size: Vec2::splat(0.5), } } } diff --git a/crates/bevy_render/src/mesh/primitives/ellipse.rs b/crates/bevy_render/src/mesh/primitives/ellipse.rs index 50978723b8fe0..7c7d606db52f3 100644 --- a/crates/bevy_render/src/mesh/primitives/ellipse.rs +++ b/crates/bevy_render/src/mesh/primitives/ellipse.rs @@ -4,7 +4,7 @@ use crate::{ }; use super::{Facing, MeshFacingExtension, Meshable}; -use bevy_math::{primitives::Ellipse, Vec3}; +use bevy_math::{primitives::Ellipse, Vec2, Vec3}; use wgpu::PrimitiveTopology; /// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. @@ -45,8 +45,7 @@ impl EllipseMeshBuilder { pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { Self { ellipse: Ellipse { - half_width, - half_height, + half_size: Vec2::new(half_width, half_height), }, resolution, facing: Facing::Z, @@ -111,8 +110,8 @@ impl EllipseMeshBuilder { // Compute vertex position at angle theta let theta = start_angle + i as f32 * step; let (sin, cos) = theta.sin_cos(); - let x = cos * self.ellipse.half_width; - let y = sin * self.ellipse.half_height; + let x = cos * self.ellipse.half_size.x; + let y = sin * self.ellipse.half_size.y; // Transform vertex position based on facing direction let position = match self.facing { diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs index 5c10e982ce659..82ba8d31b19f8 100644 --- a/crates/bevy_render/src/mesh/primitives/rectangle.rs +++ b/crates/bevy_render/src/mesh/primitives/rectangle.rs @@ -33,7 +33,7 @@ impl RectangleMeshBuilder { /// Builds a [`Mesh`] based on the configuration in `self`. pub fn build(&self) -> Mesh { - let [hw, hh] = [self.rectangle.half_width, self.rectangle.half_height]; + let [hw, hh] = [self.rectangle.half_size.x, self.rectangle.half_size.y]; let positions = match self.facing { Facing::Z | Facing::NegZ => vec![ [hw, hh, 0.0], diff --git a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs index 0f0fdd983484b..3cc1af663c89a 100644 --- a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs +++ b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs @@ -1,5 +1,8 @@ use super::{Facing, Mesh, MeshFacingExtension, Meshable}; -use bevy_math::primitives::{Ellipse, RegularPolygon}; +use bevy_math::{ + primitives::{Ellipse, RegularPolygon}, + Vec2, +}; /// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape. #[derive(Clone, Copy, Debug, Default)] @@ -38,8 +41,7 @@ impl RegularPolygonMeshBuilder { pub fn build(&self) -> Mesh { // The ellipse mesh is just a regular polygon with two radii Ellipse { - half_width: self.polygon.circumcircle.radius, - half_height: self.polygon.circumcircle.radius, + half_size: Vec2::splat(self.polygon.circumcircle.radius), } .mesh() .resolution(self.polygon.sides) diff --git a/examples/2d/2d_shapes.rs b/examples/2d/2d_shapes.rs index b3bce026f60dd..8e34cd918b70b 100644 --- a/examples/2d/2d_shapes.rs +++ b/examples/2d/2d_shapes.rs @@ -26,7 +26,7 @@ fn setup( // Ellipse commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(primitives::Ellipse::new(50.0, 100.0)).into(), + mesh: meshes.add(primitives::Ellipse::new(25.0, 50.0)).into(), material: materials.add(Color::TURQUOISE), transform: Transform::from_translation(Vec3::new(-100.0, 0.0, 0.0)), ..default() From 681dca67ac40dab1e6ba14d0bc02e2c927d32091 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Sun, 21 Jan 2024 00:38:38 +0200 Subject: [PATCH 13/19] Remove `primitives::` prefix --- examples/2d/2d_shapes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/2d/2d_shapes.rs b/examples/2d/2d_shapes.rs index 8e34cd918b70b..6ac3736a53851 100644 --- a/examples/2d/2d_shapes.rs +++ b/examples/2d/2d_shapes.rs @@ -18,7 +18,7 @@ fn setup( // Circle commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(primitives::Circle { radius: 50.0 }).into(), + mesh: meshes.add(Circle { radius: 50.0 }).into(), material: materials.add(Color::VIOLET), transform: Transform::from_translation(Vec3::new(-225.0, 0.0, 0.0)), ..default() @@ -26,7 +26,7 @@ fn setup( // Ellipse commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(primitives::Ellipse::new(25.0, 50.0)).into(), + mesh: meshes.add(Ellipse::new(25.0, 50.0)).into(), material: materials.add(Color::TURQUOISE), transform: Transform::from_translation(Vec3::new(-100.0, 0.0, 0.0)), ..default() @@ -34,7 +34,7 @@ fn setup( // Rectangle commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(primitives::Rectangle::new(50.0, 100.0)).into(), + mesh: meshes.add(Rectangle::new(50.0, 100.0)).into(), material: materials.add(Color::LIME_GREEN), transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)), ..default() @@ -42,7 +42,7 @@ fn setup( // Hexagon commands.spawn(MaterialMesh2dBundle { - mesh: meshes.add(primitives::RegularPolygon::new(50.0, 6)).into(), + mesh: meshes.add(RegularPolygon::new(50.0, 6)).into(), material: materials.add(Color::YELLOW), transform: Transform::from_translation(Vec3::new(125.0, 0.0, 0.0)), ..default() @@ -51,7 +51,7 @@ fn setup( // Triangle commands.spawn(MaterialMesh2dBundle { mesh: meshes - .add(primitives::Triangle2d::new( + .add(Triangle2d::new( Vec2::Y * 50.0, Vec2::new(-50.0, -50.0), Vec2::new(50.0, -50.0), From a4b9b5c4f65f495cde29c252456fbfd7befa8b61 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 22:08:07 +0200 Subject: [PATCH 14/19] Remove mesh facing logic --- crates/bevy_render/src/lib.rs | 6 +- .../bevy_render/src/mesh/primitives/circle.rs | 16 +--- .../src/mesh/primitives/ellipse.rs | 81 ++++------------ crates/bevy_render/src/mesh/primitives/mod.rs | 92 ------------------- .../src/mesh/primitives/rectangle.rs | 56 ++--------- .../src/mesh/primitives/regular_polygon.rs | 20 +--- .../src/mesh/primitives/triangle.rs | 34 ++----- 7 files changed, 37 insertions(+), 268 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index ede32fbfa5e72..cf83d8b99adc6 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -34,11 +34,7 @@ pub mod prelude { Projection, }, color::Color, - mesh::{ - morph::MorphWeights, - primitives::{Facing, MeshFacingExtension, Meshable}, - shape, Mesh, - }, + mesh::{morph::MorphWeights, primitives::Meshable, shape, Mesh}, render_resource::Shader, spatial_bundle::SpatialBundle, texture::{Image, ImagePlugin}, diff --git a/crates/bevy_render/src/mesh/primitives/circle.rs b/crates/bevy_render/src/mesh/primitives/circle.rs index c194067338889..df51bc14041c1 100644 --- a/crates/bevy_render/src/mesh/primitives/circle.rs +++ b/crates/bevy_render/src/mesh/primitives/circle.rs @@ -1,6 +1,6 @@ use crate::mesh::Mesh; -use super::{Facing, MeshFacingExtension, Meshable}; +use super::Meshable; use bevy_math::primitives::{Circle, RegularPolygon}; /// A builder used for creating a [`Mesh`] with a [`Circle`] shape. @@ -12,9 +12,6 @@ pub struct CircleMeshBuilder { /// The default is `32`. #[doc(alias = "vertices")] pub resolution: usize, - /// The XYZ direction that the mesh is facing. - /// The default is [`Facing::Z`]. - pub facing: Facing, } impl Default for CircleMeshBuilder { @@ -22,19 +19,10 @@ impl Default for CircleMeshBuilder { Self { circle: Circle::default(), resolution: 32, - facing: Facing::Z, } } } -impl MeshFacingExtension for CircleMeshBuilder { - #[inline] - fn facing(mut self, facing: Facing) -> Self { - self.facing = facing; - self - } -} - impl CircleMeshBuilder { /// Creates a new [`CircleMeshBuilder`] from a given radius and vertex count. #[inline] @@ -42,7 +30,6 @@ impl CircleMeshBuilder { Self { circle: Circle { radius }, resolution, - facing: Facing::Z, } } @@ -58,7 +45,6 @@ impl CircleMeshBuilder { pub fn build(&self) -> Mesh { RegularPolygon::new(self.circle.radius, self.resolution) .mesh() - .facing(self.facing) .build() } } diff --git a/crates/bevy_render/src/mesh/primitives/ellipse.rs b/crates/bevy_render/src/mesh/primitives/ellipse.rs index 7c7d606db52f3..209052b9d8e30 100644 --- a/crates/bevy_render/src/mesh/primitives/ellipse.rs +++ b/crates/bevy_render/src/mesh/primitives/ellipse.rs @@ -3,8 +3,8 @@ use crate::{ render_asset::RenderAssetPersistencePolicy, }; -use super::{Facing, MeshFacingExtension, Meshable}; -use bevy_math::{primitives::Ellipse, Vec2, Vec3}; +use super::Meshable; +use bevy_math::{primitives::Ellipse, Vec2}; use wgpu::PrimitiveTopology; /// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. @@ -16,9 +16,6 @@ pub struct EllipseMeshBuilder { /// The default is `32`. #[doc(alias = "vertices")] pub resolution: usize, - /// The XYZ direction that the mesh is facing. - /// The default is [`Facing::Z`]. - pub facing: Facing, } impl Default for EllipseMeshBuilder { @@ -26,19 +23,10 @@ impl Default for EllipseMeshBuilder { Self { ellipse: Ellipse::default(), resolution: 32, - facing: Facing::Z, } } } -impl MeshFacingExtension for EllipseMeshBuilder { - #[inline] - fn facing(mut self, facing: Facing) -> Self { - self.facing = facing; - self - } -} - impl EllipseMeshBuilder { /// Creates a new [`EllipseMeshBuilder`] from a given half width and half height and a vertex count. #[inline] @@ -48,7 +36,6 @@ impl EllipseMeshBuilder { half_size: Vec2::new(half_width, half_height), }, resolution, - facing: Facing::Z, } } @@ -64,70 +51,36 @@ impl EllipseMeshBuilder { pub fn build(&self) -> Mesh { let mut indices = Vec::with_capacity((self.resolution - 2) * 3); let mut positions = Vec::with_capacity(self.resolution); - let mut normals = Vec::with_capacity(self.resolution); + let normals = vec![[0.0, 0.0, 1.0]; self.resolution]; let mut uvs = Vec::with_capacity(self.resolution); - self.build_mesh_data( - Vec3::ZERO, - &mut indices, - &mut positions, - &mut normals, - &mut uvs, - ); - - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetPersistencePolicy::Keep, - ) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) - .with_indices(Some(Indices::U32(indices))) - } - - /// Builds the ellipse mesh and pushes the data to the given vertex attribute data sets. - pub(super) fn build_mesh_data( - &self, - translation: Vec3, - indices: &mut Vec, - positions: &mut Vec<[f32; 3]>, - normals: &mut Vec<[f32; 3]>, - uvs: &mut Vec<[f32; 2]>, - ) { - let sides = self.resolution; - let facing_coords = self.facing.to_array(); - let normal_sign = self.facing.signum() as f32; - - // The mesh could have existing vertices, so we add an offset to find - // the index where the ellipse's own vertices begin. - let index_offset = positions.len() as u32; - // Add pi/2 so that there is a vertex at the top (sin is 1.0 and cos is 0.0) let start_angle = std::f32::consts::FRAC_PI_2; - let step = normal_sign * std::f32::consts::TAU / sides as f32; + let step = std::f32::consts::TAU / self.resolution as f32; - for i in 0..sides { + for i in 0..self.resolution { // Compute vertex position at angle theta let theta = start_angle + i as f32 * step; let (sin, cos) = theta.sin_cos(); let x = cos * self.ellipse.half_size.x; let y = sin * self.ellipse.half_size.y; - // Transform vertex position based on facing direction - let position = match self.facing { - Facing::X | Facing::NegX => Vec3::new(0.0, y, -x), - Facing::Y | Facing::NegY => Vec3::new(x, 0.0, -y), - Facing::Z | Facing::NegZ => Vec3::new(x, y, 0.0), - }; - - positions.push((position + translation).to_array()); - normals.push(facing_coords); + positions.push([x, y, 0.0]); uvs.push([0.5 * (cos + 1.0), 1.0 - 0.5 * (sin + 1.0)]); } - for i in 1..(sides as u32 - 1) { - indices.extend_from_slice(&[index_offset, index_offset + i, index_offset + i + 1]); + for i in 1..(self.resolution as u32 - 1) { + indices.extend_from_slice(&[0, i, i + 1]); } + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_indices(Some(Indices::U32(indices))) } } diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 92c573c1f497d..66edb397c008c 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -58,95 +58,3 @@ pub trait Meshable { /// Creates a [`Mesh`] for a shape. fn mesh(&self) -> Self::Output; } - -/// The cartesian axis that a [`Mesh`] should be facing upon creation. -/// This is either positive or negative `X`, `Y`, or `Z`. -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub enum Facing { - /// Facing the `+X` direction. - X = 1, - /// Facing the `+Y` direction. - Y = 2, - /// Facing the `+Z` direction. - #[default] - Z = 3, - /// Facing the `-X` direction. - NegX = -1, - /// Facing the `-Y` direction. - NegY = -2, - /// Facing the `-Z` direction. - NegZ = -3, -} - -impl Facing { - /// Returns `1` if the facing direction is positive `X`, `Y`, or `Z`, and `-1` otherwise. - #[inline] - pub const fn signum(&self) -> i8 { - match self { - Facing::X | Facing::Y | Facing::Z => 1, - _ => -1, - } - } - - /// Returns the direction as an array in the format `[x, y, z]`. - /// - /// # Example - /// - /// ``` - /// # use bevy_render::prelude::Facing; - /// assert_eq!(Facing::X.to_array(), [1.0, 0.0, 0.0]); - /// ``` - #[inline] - pub const fn to_array(&self) -> [f32; 3] { - match self { - Facing::X => [1.0, 0.0, 0.0], - Facing::Y => [0.0, 1.0, 0.0], - Facing::Z => [0.0, 0.0, 1.0], - Facing::NegX => [-1.0, 0.0, 0.0], - Facing::NegY => [0.0, -1.0, 0.0], - Facing::NegZ => [0.0, 0.0, -1.0], - } - } -} - -/// An extension trait for methods related to setting a specific [`Facing`] direction. -pub trait MeshFacingExtension: Sized { - /// Set the [`Facing`] direction. - fn facing(self, facing: Facing) -> Self; - - /// Set the [`Facing`] direction to `+X`. - #[inline] - fn facing_x(self) -> Self { - self.facing(Facing::X) - } - - /// Set the [`Facing`] direction to `+Y`. - #[inline] - fn facing_y(self) -> Self { - self.facing(Facing::Y) - } - - /// Set the [`Facing`] direction to `+Z`. - #[inline] - fn facing_z(self) -> Self { - self.facing(Facing::Z) - } - - /// Set the [`Facing`] direction to `-X`. - #[inline] - fn facing_neg_x(self) -> Self { - self.facing(Facing::NegX) - } - - /// Set the [`Facing`] direction to `-Y`. - #[inline] - fn facing_neg_y(self) -> Self { - self.facing(Facing::NegY) - } - - /// Set the [`Facing`] direction to `-Z`. - #[inline] - fn facing_neg_z(self) -> Self { - self.facing(Facing::NegZ) - } -} diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs index 82ba8d31b19f8..5f90617eae787 100644 --- a/crates/bevy_render/src/mesh/primitives/rectangle.rs +++ b/crates/bevy_render/src/mesh/primitives/rectangle.rs @@ -1,4 +1,4 @@ -use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use super::{Mesh, Meshable}; use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; use bevy_math::primitives::Rectangle; use wgpu::PrimitiveTopology; @@ -8,17 +8,6 @@ use wgpu::PrimitiveTopology; pub struct RectangleMeshBuilder { /// The [`Rectangle`] shape. pub rectangle: Rectangle, - /// The XYZ direction that the mesh is facing. - /// The default is [`Facing::Z`]. - pub facing: Facing, -} - -impl MeshFacingExtension for RectangleMeshBuilder { - #[inline] - fn facing(mut self, facing: Facing) -> Self { - self.facing = facing; - self - } } impl RectangleMeshBuilder { @@ -27,43 +16,21 @@ impl RectangleMeshBuilder { pub fn new(width: f32, height: f32) -> Self { Self { rectangle: Rectangle::new(width, height), - facing: Facing::Z, } } /// Builds a [`Mesh`] based on the configuration in `self`. pub fn build(&self) -> Mesh { let [hw, hh] = [self.rectangle.half_size.x, self.rectangle.half_size.y]; - let positions = match self.facing { - Facing::Z | Facing::NegZ => vec![ - [hw, hh, 0.0], - [-hw, hh, 0.0], - [-hw, -hh, 0.0], - [hw, -hh, 0.0], - ], - Facing::Y | Facing::NegY => vec![ - [hw, 0.0, -hh], - [-hw, 0.0, -hh], - [-hw, 0.0, hh], - [hw, 0.0, hh], - ], - Facing::X | Facing::NegX => vec![ - [0.0, hh, -hw], - [0.0, hh, hw], - [0.0, -hh, hw], - [0.0, -hh, -hw], - ], - }; - - let normals = vec![self.facing.to_array(); 4]; + let positions = vec![ + [hw, hh, 0.0], + [-hw, hh, 0.0], + [-hw, -hh, 0.0], + [hw, -hh, 0.0], + ]; + let normals = vec![[0.0, 0.0, 1.0]; 4]; let uvs = vec![[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]]; - - // Flip indices if facing -X, -Y, or -Z - let indices = if self.facing.signum() > 0 { - Indices::U32(vec![0, 1, 2, 0, 2, 3]) - } else { - Indices::U32(vec![0, 2, 1, 0, 3, 2]) - }; + let indices = Indices::U32(vec![0, 1, 2, 0, 2, 3]); Mesh::new( PrimitiveTopology::TriangleList, @@ -80,10 +47,7 @@ impl Meshable for Rectangle { type Output = RectangleMeshBuilder; fn mesh(&self) -> Self::Output { - RectangleMeshBuilder { - rectangle: *self, - ..Default::default() - } + RectangleMeshBuilder { rectangle: *self } } } diff --git a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs index 3cc1af663c89a..473bd7b6863fa 100644 --- a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs +++ b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs @@ -1,4 +1,4 @@ -use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use super::{Mesh, Meshable}; use bevy_math::{ primitives::{Ellipse, RegularPolygon}, Vec2, @@ -9,17 +9,6 @@ use bevy_math::{ pub struct RegularPolygonMeshBuilder { /// The [`RegularPolygon`] shape. pub polygon: RegularPolygon, - /// The XYZ direction that the mesh is facing. - /// The default is [`Facing::Z`]. - pub facing: Facing, -} - -impl MeshFacingExtension for RegularPolygonMeshBuilder { - #[inline] - fn facing(mut self, facing: Facing) -> Self { - self.facing = facing; - self - } } impl RegularPolygonMeshBuilder { @@ -33,7 +22,6 @@ impl RegularPolygonMeshBuilder { pub fn new(circumradius: f32, sides: usize) -> Self { Self { polygon: RegularPolygon::new(circumradius, sides), - ..Default::default() } } @@ -45,7 +33,6 @@ impl RegularPolygonMeshBuilder { } .mesh() .resolution(self.polygon.sides) - .facing(self.facing) .build() } } @@ -54,10 +41,7 @@ impl Meshable for RegularPolygon { type Output = RegularPolygonMeshBuilder; fn mesh(&self) -> Self::Output { - RegularPolygonMeshBuilder { - polygon: *self, - ..Default::default() - } + RegularPolygonMeshBuilder { polygon: *self } } } diff --git a/crates/bevy_render/src/mesh/primitives/triangle.rs b/crates/bevy_render/src/mesh/primitives/triangle.rs index 699b09985d824..81fd4cfb170ed 100644 --- a/crates/bevy_render/src/mesh/primitives/triangle.rs +++ b/crates/bevy_render/src/mesh/primitives/triangle.rs @@ -1,4 +1,4 @@ -use super::{Facing, Mesh, MeshFacingExtension, Meshable}; +use super::{Mesh, Meshable}; use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; use bevy_math::{ primitives::{Triangle2d, WindingOrder}, @@ -11,17 +11,6 @@ use wgpu::PrimitiveTopology; pub struct Triangle2dMeshBuilder { /// The [`Triangle2d`] shape. pub triangle: Triangle2d, - /// The XYZ direction that the mesh is facing. - /// The default is [`Facing::Z`]. - pub facing: Facing, -} - -impl MeshFacingExtension for Triangle2dMeshBuilder { - #[inline] - fn facing(mut self, facing: Facing) -> Self { - self.facing = facing; - self - } } impl Triangle2dMeshBuilder { @@ -30,7 +19,6 @@ impl Triangle2dMeshBuilder { pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { Self { triangle: Triangle2d::new(a, b, c), - facing: Facing::Z, } } @@ -38,13 +26,8 @@ impl Triangle2dMeshBuilder { pub fn build(&self) -> Mesh { let [a, b, c] = self.triangle.vertices; - let positions = match self.facing { - Facing::X | Facing::NegX => [[0.0, a.y, -a.x], [0.0, b.y, -b.x], [0.0, c.y, -c.x]], - Facing::Y | Facing::NegY => [[a.x, 0.0, -a.y], [b.x, 0.0, -b.y], [c.x, 0.0, -c.y]], - Facing::Z | Facing::NegZ => [[a.x, a.y, 0.0], [b.x, b.y, 0.0], [c.x, c.y, 0.0]], - }; - - let normals = vec![self.facing.to_array(); 3]; + let positions = vec![[a.x, a.y, 0.0], [b.x, b.y, 0.0], [c.x, c.y, 0.0]]; + let normals = vec![[0.0, 0.0, 1.0]; 3]; // The extents of the bounding box of the triangle, // used to compute the UV coordinates of the points. @@ -55,10 +38,8 @@ impl Triangle2dMeshBuilder { c / extents / 2.0 + 0.5, ]; - let flipped = self.facing.signum() < 0; let is_ccw = self.triangle.winding_order() == WindingOrder::CounterClockwise; - let is_cw = self.triangle.winding_order() == WindingOrder::Clockwise; - let indices = if (is_ccw && !flipped) || (is_cw && flipped) { + let indices = if is_ccw { Indices::U32(vec![0, 1, 2]) } else { Indices::U32(vec![0, 2, 1]) @@ -69,7 +50,7 @@ impl Triangle2dMeshBuilder { RenderAssetPersistencePolicy::Keep, ) .with_indices(Some(indices)) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, Vec::from(positions)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } @@ -79,10 +60,7 @@ impl Meshable for Triangle2d { type Output = Triangle2dMeshBuilder; fn mesh(&self) -> Triangle2dMeshBuilder { - Triangle2dMeshBuilder { - triangle: *self, - ..Default::default() - } + Triangle2dMeshBuilder { triangle: *self } } } From 76108350ab73cf8a6997df9cafeb0a33e750e293 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 22:27:44 +0200 Subject: [PATCH 15/19] Move 2D meshes to single file and remove unnecessary builders --- .../bevy_render/src/mesh/primitives/circle.rs | 73 ----- .../bevy_render/src/mesh/primitives/dim2.rs | 272 ++++++++++++++++++ .../src/mesh/primitives/ellipse.rs | 108 ------- crates/bevy_render/src/mesh/primitives/mod.rs | 15 +- .../src/mesh/primitives/rectangle.rs | 64 ----- .../src/mesh/primitives/regular_polygon.rs | 58 ---- .../src/mesh/primitives/triangle.rs | 77 ----- 7 files changed, 274 insertions(+), 393 deletions(-) delete mode 100644 crates/bevy_render/src/mesh/primitives/circle.rs create mode 100644 crates/bevy_render/src/mesh/primitives/dim2.rs delete mode 100644 crates/bevy_render/src/mesh/primitives/ellipse.rs delete mode 100644 crates/bevy_render/src/mesh/primitives/rectangle.rs delete mode 100644 crates/bevy_render/src/mesh/primitives/regular_polygon.rs delete mode 100644 crates/bevy_render/src/mesh/primitives/triangle.rs diff --git a/crates/bevy_render/src/mesh/primitives/circle.rs b/crates/bevy_render/src/mesh/primitives/circle.rs deleted file mode 100644 index df51bc14041c1..0000000000000 --- a/crates/bevy_render/src/mesh/primitives/circle.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::mesh::Mesh; - -use super::Meshable; -use bevy_math::primitives::{Circle, RegularPolygon}; - -/// A builder used for creating a [`Mesh`] with a [`Circle`] shape. -#[derive(Clone, Copy, Debug)] -pub struct CircleMeshBuilder { - /// The [`Circle`] shape. - pub circle: Circle, - /// The number of vertices used for the circle mesh. - /// The default is `32`. - #[doc(alias = "vertices")] - pub resolution: usize, -} - -impl Default for CircleMeshBuilder { - fn default() -> Self { - Self { - circle: Circle::default(), - resolution: 32, - } - } -} - -impl CircleMeshBuilder { - /// Creates a new [`CircleMeshBuilder`] from a given radius and vertex count. - #[inline] - pub const fn new(radius: f32, resolution: usize) -> Self { - Self { - circle: Circle { radius }, - resolution, - } - } - - /// Sets the number of vertices used for the circle mesh. - #[inline] - #[doc(alias = "vertices")] - pub const fn resolution(mut self, resolution: usize) -> Self { - self.resolution = resolution; - self - } - - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { - RegularPolygon::new(self.circle.radius, self.resolution) - .mesh() - .build() - } -} - -impl Meshable for Circle { - type Output = CircleMeshBuilder; - - fn mesh(&self) -> Self::Output { - CircleMeshBuilder { - circle: *self, - ..Default::default() - } - } -} - -impl From for Mesh { - fn from(circle: Circle) -> Self { - circle.mesh().build() - } -} - -impl From for Mesh { - fn from(circle: CircleMeshBuilder) -> Self { - circle.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/dim2.rs b/crates/bevy_render/src/mesh/primitives/dim2.rs new file mode 100644 index 0000000000000..cbec1d1245d51 --- /dev/null +++ b/crates/bevy_render/src/mesh/primitives/dim2.rs @@ -0,0 +1,272 @@ +use crate::{ + mesh::{Indices, Mesh}, + render_asset::RenderAssetPersistencePolicy, +}; + +use super::Meshable; +use bevy_math::{ + primitives::{Circle, Ellipse, Rectangle, RegularPolygon, Triangle2d, WindingOrder}, + Vec2, +}; +use wgpu::PrimitiveTopology; + +/// A builder used for creating a [`Mesh`] with a [`Circle`] shape. +#[derive(Clone, Copy, Debug)] +pub struct CircleMeshBuilder { + /// The [`Circle`] shape. + pub circle: Circle, + /// The number of vertices used for the circle mesh. + /// The default is `32`. + #[doc(alias = "vertices")] + pub resolution: usize, +} + +impl Default for CircleMeshBuilder { + fn default() -> Self { + Self { + circle: Circle::default(), + resolution: 32, + } + } +} + +impl CircleMeshBuilder { + /// Creates a new [`CircleMeshBuilder`] from a given radius and vertex count. + #[inline] + pub const fn new(radius: f32, resolution: usize) -> Self { + Self { + circle: Circle { radius }, + resolution, + } + } + + /// Sets the number of vertices used for the circle mesh. + #[inline] + #[doc(alias = "vertices")] + pub const fn resolution(mut self, resolution: usize) -> Self { + self.resolution = resolution; + self + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub fn build(&self) -> Mesh { + RegularPolygon::new(self.circle.radius, self.resolution).mesh() + } +} + +impl Meshable for Circle { + type Output = CircleMeshBuilder; + + fn mesh(&self) -> Self::Output { + CircleMeshBuilder { + circle: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(circle: Circle) -> Self { + circle.mesh().build() + } +} + +impl From for Mesh { + fn from(circle: CircleMeshBuilder) -> Self { + circle.build() + } +} + +impl Meshable for RegularPolygon { + type Output = Mesh; + + fn mesh(&self) -> Self::Output { + // The ellipse mesh is just a regular polygon with two radii + Ellipse { + half_size: Vec2::splat(self.circumcircle.radius), + } + .mesh() + .resolution(self.sides) + .build() + } +} + +impl From for Mesh { + fn from(polygon: RegularPolygon) -> Self { + polygon.mesh() + } +} + +/// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. +#[derive(Clone, Copy, Debug)] +pub struct EllipseMeshBuilder { + /// The [`Ellipse`] shape. + pub ellipse: Ellipse, + /// The number of vertices used for the ellipse mesh. + /// The default is `32`. + #[doc(alias = "vertices")] + pub resolution: usize, +} + +impl Default for EllipseMeshBuilder { + fn default() -> Self { + Self { + ellipse: Ellipse::default(), + resolution: 32, + } + } +} + +impl EllipseMeshBuilder { + /// Creates a new [`EllipseMeshBuilder`] from a given half width and half height and a vertex count. + #[inline] + pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { + Self { + ellipse: Ellipse { + half_size: Vec2::new(half_width, half_height), + }, + resolution, + } + } + + /// Sets the number of vertices used for the ellipse mesh. + #[inline] + #[doc(alias = "vertices")] + pub const fn resolution(mut self, resolution: usize) -> Self { + self.resolution = resolution; + self + } + + /// Builds a [`Mesh`] based on the configuration in `self`. + pub 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]; + let mut uvs = Vec::with_capacity(self.resolution); + + // Add pi/2 so that there is a vertex at the top (sin is 1.0 and cos is 0.0) + let start_angle = std::f32::consts::FRAC_PI_2; + let step = std::f32::consts::TAU / self.resolution as f32; + + for i in 0..self.resolution { + // Compute vertex position at angle theta + let theta = start_angle + i as f32 * step; + let (sin, cos) = theta.sin_cos(); + let x = cos * self.ellipse.half_size.x; + let y = sin * self.ellipse.half_size.y; + + positions.push([x, y, 0.0]); + uvs.push([0.5 * (cos + 1.0), 1.0 - 0.5 * (sin + 1.0)]); + } + + for i in 1..(self.resolution as u32 - 1) { + indices.extend_from_slice(&[0, i, i + 1]); + } + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_indices(Some(Indices::U32(indices))) + } +} + +impl Meshable for Ellipse { + type Output = EllipseMeshBuilder; + + fn mesh(&self) -> Self::Output { + EllipseMeshBuilder { + ellipse: *self, + ..Default::default() + } + } +} + +impl From for Mesh { + fn from(ellipse: Ellipse) -> Self { + ellipse.mesh().build() + } +} + +impl From for Mesh { + fn from(ellipse: EllipseMeshBuilder) -> Self { + ellipse.build() + } +} + +impl Meshable for Triangle2d { + type Output = Mesh; + + fn mesh(&self) -> Self::Output { + let [a, b, c] = self.vertices; + + let positions = vec![[a.x, a.y, 0.0], [b.x, b.y, 0.0], [c.x, c.y, 0.0]]; + let normals = vec![[0.0, 0.0, 1.0]; 3]; + + // The extents of the bounding box of the triangle, + // used to compute the UV coordinates of the points. + let extents = a.min(b).min(c).abs().max(a.max(b).max(c)) * Vec2::new(1.0, -1.0); + let uvs = vec![ + a / extents / 2.0 + 0.5, + b / extents / 2.0 + 0.5, + c / extents / 2.0 + 0.5, + ]; + + let is_ccw = self.winding_order() == WindingOrder::CounterClockwise; + let indices = if is_ccw { + Indices::U32(vec![0, 1, 2]) + } else { + Indices::U32(vec![0, 2, 1]) + }; + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + } +} + +impl From for Mesh { + fn from(triangle: Triangle2d) -> Self { + triangle.mesh() + } +} + +impl Meshable for Rectangle { + type Output = Mesh; + + fn mesh(&self) -> Self::Output { + let [hw, hh] = [self.half_size.x, self.half_size.y]; + let positions = vec![ + [hw, hh, 0.0], + [-hw, hh, 0.0], + [-hw, -hh, 0.0], + [hw, -hh, 0.0], + ]; + let normals = vec![[0.0, 0.0, 1.0]; 4]; + let uvs = vec![[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]]; + let indices = Indices::U32(vec![0, 1, 2, 0, 2, 3]); + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetPersistencePolicy::Keep, + ) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + } +} + +impl From for Mesh { + fn from(rectangle: Rectangle) -> Self { + rectangle.mesh() + } +} diff --git a/crates/bevy_render/src/mesh/primitives/ellipse.rs b/crates/bevy_render/src/mesh/primitives/ellipse.rs deleted file mode 100644 index 209052b9d8e30..0000000000000 --- a/crates/bevy_render/src/mesh/primitives/ellipse.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::{ - mesh::{Indices, Mesh}, - render_asset::RenderAssetPersistencePolicy, -}; - -use super::Meshable; -use bevy_math::{primitives::Ellipse, Vec2}; -use wgpu::PrimitiveTopology; - -/// A builder used for creating a [`Mesh`] with an [`Ellipse`] shape. -#[derive(Clone, Copy, Debug)] -pub struct EllipseMeshBuilder { - /// The [`Ellipse`] shape. - pub ellipse: Ellipse, - /// The number of vertices used for the ellipse mesh. - /// The default is `32`. - #[doc(alias = "vertices")] - pub resolution: usize, -} - -impl Default for EllipseMeshBuilder { - fn default() -> Self { - Self { - ellipse: Ellipse::default(), - resolution: 32, - } - } -} - -impl EllipseMeshBuilder { - /// Creates a new [`EllipseMeshBuilder`] from a given half width and half height and a vertex count. - #[inline] - pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { - Self { - ellipse: Ellipse { - half_size: Vec2::new(half_width, half_height), - }, - resolution, - } - } - - /// Sets the number of vertices used for the ellipse mesh. - #[inline] - #[doc(alias = "vertices")] - pub const fn resolution(mut self, resolution: usize) -> Self { - self.resolution = resolution; - self - } - - /// Builds a [`Mesh`] based on the configuration in `self`. - pub 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]; - let mut uvs = Vec::with_capacity(self.resolution); - - // Add pi/2 so that there is a vertex at the top (sin is 1.0 and cos is 0.0) - let start_angle = std::f32::consts::FRAC_PI_2; - let step = std::f32::consts::TAU / self.resolution as f32; - - for i in 0..self.resolution { - // Compute vertex position at angle theta - let theta = start_angle + i as f32 * step; - let (sin, cos) = theta.sin_cos(); - let x = cos * self.ellipse.half_size.x; - let y = sin * self.ellipse.half_size.y; - - positions.push([x, y, 0.0]); - uvs.push([0.5 * (cos + 1.0), 1.0 - 0.5 * (sin + 1.0)]); - } - - for i in 1..(self.resolution as u32 - 1) { - indices.extend_from_slice(&[0, i, i + 1]); - } - - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetPersistencePolicy::Keep, - ) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) - .with_indices(Some(Indices::U32(indices))) - } -} - -impl Meshable for Ellipse { - type Output = EllipseMeshBuilder; - - fn mesh(&self) -> Self::Output { - EllipseMeshBuilder { - ellipse: *self, - ..Default::default() - } - } -} - -impl From for Mesh { - fn from(ellipse: Ellipse) -> Self { - ellipse.mesh().build() - } -} - -impl From for Mesh { - fn from(ellipse: EllipseMeshBuilder) -> Self { - ellipse.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 66edb397c008c..930b7fa40b279 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -35,19 +35,8 @@ #![warn(missing_docs)] -mod circle; -mod ellipse; -mod rectangle; -mod regular_polygon; -mod triangle; - -pub use circle::CircleMeshBuilder; -pub use ellipse::EllipseMeshBuilder; -pub use rectangle::RectangleMeshBuilder; -pub use regular_polygon::RegularPolygonMeshBuilder; -pub use triangle::Triangle2dMeshBuilder; - -use super::Mesh; +mod dim2; +pub use dim2::{CircleMeshBuilder, EllipseMeshBuilder}; /// A trait for shapes that can be turned into a [`Mesh`]. pub trait Meshable { diff --git a/crates/bevy_render/src/mesh/primitives/rectangle.rs b/crates/bevy_render/src/mesh/primitives/rectangle.rs deleted file mode 100644 index 5f90617eae787..0000000000000 --- a/crates/bevy_render/src/mesh/primitives/rectangle.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::{Mesh, Meshable}; -use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; -use bevy_math::primitives::Rectangle; -use wgpu::PrimitiveTopology; - -/// A builder used for creating a [`Mesh`] with a [`Rectangle`] shape. -#[derive(Clone, Copy, Debug, Default)] -pub struct RectangleMeshBuilder { - /// The [`Rectangle`] shape. - pub rectangle: Rectangle, -} - -impl RectangleMeshBuilder { - /// Creates a new [`RectangleMeshBuilder`] from a given `width` and `height`. - #[inline] - pub fn new(width: f32, height: f32) -> Self { - Self { - rectangle: Rectangle::new(width, height), - } - } - - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { - let [hw, hh] = [self.rectangle.half_size.x, self.rectangle.half_size.y]; - let positions = vec![ - [hw, hh, 0.0], - [-hw, hh, 0.0], - [-hw, -hh, 0.0], - [hw, -hh, 0.0], - ]; - let normals = vec![[0.0, 0.0, 1.0]; 4]; - let uvs = vec![[1.0, 0.0], [0.0, 0.0], [0.0, 1.0], [1.0, 1.0]]; - let indices = Indices::U32(vec![0, 1, 2, 0, 2, 3]); - - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetPersistencePolicy::Keep, - ) - .with_indices(Some(indices)) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) - } -} - -impl Meshable for Rectangle { - type Output = RectangleMeshBuilder; - - fn mesh(&self) -> Self::Output { - RectangleMeshBuilder { rectangle: *self } - } -} - -impl From for Mesh { - fn from(rectangle: Rectangle) -> Self { - rectangle.mesh().build() - } -} - -impl From for Mesh { - fn from(rectangle: RectangleMeshBuilder) -> Self { - rectangle.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs b/crates/bevy_render/src/mesh/primitives/regular_polygon.rs deleted file mode 100644 index 473bd7b6863fa..0000000000000 --- a/crates/bevy_render/src/mesh/primitives/regular_polygon.rs +++ /dev/null @@ -1,58 +0,0 @@ -use super::{Mesh, Meshable}; -use bevy_math::{ - primitives::{Ellipse, RegularPolygon}, - Vec2, -}; - -/// A builder used for creating a [`Mesh`] with a [`RegularPolygon`] shape. -#[derive(Clone, Copy, Debug, Default)] -pub struct RegularPolygonMeshBuilder { - /// The [`RegularPolygon`] shape. - pub polygon: RegularPolygon, -} - -impl RegularPolygonMeshBuilder { - /// Creates a new [`RegularPolygonMeshBuilder`] from the radius - /// of the circumcircle and a number of sides. - /// - /// # Panics - /// - /// Panics if `circumradius` is non-positive. - #[inline] - pub fn new(circumradius: f32, sides: usize) -> Self { - Self { - polygon: RegularPolygon::new(circumradius, sides), - } - } - - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { - // The ellipse mesh is just a regular polygon with two radii - Ellipse { - half_size: Vec2::splat(self.polygon.circumcircle.radius), - } - .mesh() - .resolution(self.polygon.sides) - .build() - } -} - -impl Meshable for RegularPolygon { - type Output = RegularPolygonMeshBuilder; - - fn mesh(&self) -> Self::Output { - RegularPolygonMeshBuilder { polygon: *self } - } -} - -impl From for Mesh { - fn from(polygon: RegularPolygon) -> Self { - polygon.mesh().build() - } -} - -impl From for Mesh { - fn from(polygon: RegularPolygonMeshBuilder) -> Self { - polygon.build() - } -} diff --git a/crates/bevy_render/src/mesh/primitives/triangle.rs b/crates/bevy_render/src/mesh/primitives/triangle.rs deleted file mode 100644 index 81fd4cfb170ed..0000000000000 --- a/crates/bevy_render/src/mesh/primitives/triangle.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::{Mesh, Meshable}; -use crate::{mesh::Indices, render_asset::RenderAssetPersistencePolicy}; -use bevy_math::{ - primitives::{Triangle2d, WindingOrder}, - Vec2, -}; -use wgpu::PrimitiveTopology; - -/// A builder used for creating a [`Mesh`] with a [`Triangle2d`] shape. -#[derive(Clone, Copy, Debug, Default)] -pub struct Triangle2dMeshBuilder { - /// The [`Triangle2d`] shape. - pub triangle: Triangle2d, -} - -impl Triangle2dMeshBuilder { - /// Creates a new [`Triangle2dMeshBuilder`] from points `a`, `b`, and `c`. - #[inline] - pub const fn new(a: Vec2, b: Vec2, c: Vec2) -> Self { - Self { - triangle: Triangle2d::new(a, b, c), - } - } - - /// Builds a [`Mesh`] based on the configuration in `self`. - pub fn build(&self) -> Mesh { - let [a, b, c] = self.triangle.vertices; - - let positions = vec![[a.x, a.y, 0.0], [b.x, b.y, 0.0], [c.x, c.y, 0.0]]; - let normals = vec![[0.0, 0.0, 1.0]; 3]; - - // The extents of the bounding box of the triangle, - // used to compute the UV coordinates of the points. - let extents = a.min(b).min(c).abs().max(a.max(b).max(c)) * Vec2::new(1.0, -1.0); - let uvs = vec![ - a / extents / 2.0 + 0.5, - b / extents / 2.0 + 0.5, - c / extents / 2.0 + 0.5, - ]; - - let is_ccw = self.triangle.winding_order() == WindingOrder::CounterClockwise; - let indices = if is_ccw { - Indices::U32(vec![0, 1, 2]) - } else { - Indices::U32(vec![0, 2, 1]) - }; - - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetPersistencePolicy::Keep, - ) - .with_indices(Some(indices)) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) - } -} - -impl Meshable for Triangle2d { - type Output = Triangle2dMeshBuilder; - - fn mesh(&self) -> Triangle2dMeshBuilder { - Triangle2dMeshBuilder { triangle: *self } - } -} - -impl From for Mesh { - fn from(triangle: Triangle2d) -> Self { - triangle.mesh().build() - } -} - -impl From for Mesh { - fn from(triangle: Triangle2dMeshBuilder) -> Self { - triangle.build() - } -} From 942e8921ae3a49c09e764183bacb4d1c80015f13 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 22:31:05 +0200 Subject: [PATCH 16/19] Update docs --- crates/bevy_render/src/mesh/primitives/mod.rs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 930b7fa40b279..81da7586b06d1 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -1,8 +1,8 @@ //! Mesh generation for [primitive shapes](bevy_math::primitives). //! //! Primitives that support meshing implement the [`Meshable`] trait. -//! Calling [`mesh`](Meshable::mesh) will return a builder that can be used -//! to specify shape-specific configuration. +//! Calling [`mesh`](Meshable::mesh) will return either a [`Mesh`] or a builder +//! that can be used to specify shape-specific configuration for creating the [`Mesh`]. //! //! ``` //! # use bevy_asset::Assets; @@ -15,23 +15,11 @@ //! let circle = meshes.add(primitives::Circle { radius: 25.0 }); //! //! // Specify number of vertices -//! let circle = meshes.add(primitives::Circle { radius: 25.0 }.mesh().resolution(64)); +//! let circle = meshes.add(primitivesCircle { radius: 25.0 }.mesh().resolution(64)); //! # } //! ``` //! -//! Some shapes also support different facing directions through the [`Facing`] enum or builder methods. -//! -//! ``` -//! # use bevy_asset::Assets; -//! # use bevy_ecs::prelude::ResMut; -//! # use bevy_math::primitives; -//! # use bevy_render::prelude::*; -//! # -//! # fn setup(mut meshes: ResMut>) { -//! // Create rectangle mesh facing up -//! let rectangle = meshes.add(primitives::Rectangle::new(50.0, 25.0).mesh().facing_y()); -//! # } -//! ``` +//! [`Mesh`]: super::Mesh #![warn(missing_docs)] From b2c9a980bfc70d96d72289d86c7b9223482a4562 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 22:34:27 +0200 Subject: [PATCH 17/19] Fix doc example --- crates/bevy_render/src/mesh/primitives/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 81da7586b06d1..2c88d802ccb4a 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -7,15 +7,15 @@ //! ``` //! # use bevy_asset::Assets; //! # use bevy_ecs::prelude::ResMut; -//! # use bevy_math::primitives; +//! # use bevy_math::prelude::Circle; //! # use bevy_render::prelude::*; //! # //! # fn setup(mut meshes: ResMut>) { //! // Create circle mesh with default configuration -//! let circle = meshes.add(primitives::Circle { radius: 25.0 }); +//! let circle = meshes.add(Circle { radius: 25.0 }); //! //! // Specify number of vertices -//! let circle = meshes.add(primitivesCircle { radius: 25.0 }.mesh().resolution(64)); +//! let circle = meshes.add(Circle { radius: 25.0 }.mesh().resolution(64)); //! # } //! ``` //! From faeaa60c30095747fb8d5ce849f45133f53472d1 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 23:07:31 +0200 Subject: [PATCH 18/19] Fix intradoc links --- crates/bevy_render/src/mesh/primitives/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/mod.rs b/crates/bevy_render/src/mesh/primitives/mod.rs index 2c88d802ccb4a..b05b3645cfe18 100644 --- a/crates/bevy_render/src/mesh/primitives/mod.rs +++ b/crates/bevy_render/src/mesh/primitives/mod.rs @@ -1,8 +1,8 @@ //! Mesh generation for [primitive shapes](bevy_math::primitives). //! //! Primitives that support meshing implement the [`Meshable`] trait. -//! Calling [`mesh`](Meshable::mesh) will return either a [`Mesh`] or a builder -//! that can be used to specify shape-specific configuration for creating the [`Mesh`]. +//! Calling [`mesh`](Meshable::mesh) will return either a [`Mesh`](super::Mesh) or a builder +//! that can be used to specify shape-specific configuration for creating the [`Mesh`](super::Mesh). //! //! ``` //! # use bevy_asset::Assets; @@ -18,20 +18,18 @@ //! let circle = meshes.add(Circle { radius: 25.0 }.mesh().resolution(64)); //! # } //! ``` -//! -//! [`Mesh`]: super::Mesh #![warn(missing_docs)] mod dim2; pub use dim2::{CircleMeshBuilder, EllipseMeshBuilder}; -/// A trait for shapes that can be turned into a [`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`] - /// or a builder used for creating a [`Mesh`]. + /// The output of [`Self::mesh`]. This can either be a [`Mesh`](super::Mesh) + /// or a builder used for creating a [`Mesh`](super::Mesh). type Output; - /// Creates a [`Mesh`] for a shape. + /// Creates a [`Mesh`](super::Mesh) for a shape. fn mesh(&self) -> Self::Output; } From 8969134009a82ea6641006f5769de3dfafd2a7d6 Mon Sep 17 00:00:00 2001 From: Joona Aalto Date: Mon, 22 Jan 2024 23:08:56 +0200 Subject: [PATCH 19/19] Use `Ellipse::new` --- crates/bevy_render/src/mesh/primitives/dim2.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/crates/bevy_render/src/mesh/primitives/dim2.rs b/crates/bevy_render/src/mesh/primitives/dim2.rs index cbec1d1245d51..833aa0af492c3 100644 --- a/crates/bevy_render/src/mesh/primitives/dim2.rs +++ b/crates/bevy_render/src/mesh/primitives/dim2.rs @@ -82,12 +82,10 @@ impl Meshable for RegularPolygon { fn mesh(&self) -> Self::Output { // The ellipse mesh is just a regular polygon with two radii - Ellipse { - half_size: Vec2::splat(self.circumcircle.radius), - } - .mesh() - .resolution(self.sides) - .build() + Ellipse::new(self.circumcircle.radius, self.circumcircle.radius) + .mesh() + .resolution(self.sides) + .build() } } @@ -122,9 +120,7 @@ impl EllipseMeshBuilder { #[inline] pub const fn new(half_width: f32, half_height: f32, resolution: usize) -> Self { Self { - ellipse: Ellipse { - half_size: Vec2::new(half_width, half_height), - }, + ellipse: Ellipse::new(half_width, half_height), resolution, } }