Skip to content

Commit 4a23dc4

Browse files
atlv24Jondolf
andauthored
Split out bevy_mesh from bevy_render (#15666)
# Objective - bevy_render is gargantuan ## Solution - Split out bevy_mesh ## Testing - Ran some examples, everything looks fine ## Migration Guide `bevy_render::mesh::morph::inherit_weights` is now `bevy_render::mesh::inherit_weights` if you were using `Mesh::compute_aabb`, you will need to `use bevy_render::mesh::MeshAabb;` now --------- Co-authored-by: Joona Aalto <[email protected]>
1 parent 7c4a068 commit 4a23dc4

32 files changed

+1087
-1042
lines changed

crates/bevy_animation/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ impl Plugin for AnimationPlugin {
12441244
// `PostUpdate`. For now, we just disable ambiguity testing
12451245
// for this system.
12461246
animate_targets
1247-
.after(bevy_render::mesh::morph::inherit_weights)
1247+
.after(bevy_render::mesh::inherit_weights)
12481248
.ambiguous_with_all(),
12491249
trigger_untargeted_animation_events,
12501250
expire_completed_transitions,

crates/bevy_mesh/Cargo.toml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "bevy_mesh"
3+
version = "0.15.0-dev"
4+
edition = "2021"
5+
description = "Provides mesh types for Bevy Engine"
6+
homepage = "https://bevyengine.org"
7+
repository = "https://github.com/bevyengine/bevy"
8+
license = "MIT OR Apache-2.0"
9+
keywords = ["bevy"]
10+
11+
[dependencies]
12+
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
13+
bevy_image = { path = "../bevy_image", version = "0.15.0-dev" }
14+
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
15+
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
16+
"bevy",
17+
] }
18+
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
19+
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
20+
bevy_mikktspace = { path = "../bevy_mikktspace", version = "0.15.0-dev" }
21+
bevy_derive = { path = "../bevy_derive", version = "0.15.0-dev" }
22+
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
23+
24+
# misc
25+
bitflags = { version = "2.3", features = ["serde"] }
26+
bytemuck = { version = "1.5" }
27+
wgpu = { version = "22", default-features = false }
28+
serde = { version = "1", features = ["derive"] }
29+
hexasphere = "15.0"
30+
thiserror = "1.0"
31+
32+
[lints]
33+
workspace = true
34+
35+
[package.metadata.docs.rs]
36+
rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"]
37+
all-features = true

crates/bevy_render/src/mesh/mesh/conversions.rs renamed to crates/bevy_mesh/src/conversions.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
//! # Examples
55
//!
66
//! ```
7-
//! use bevy_render::mesh::VertexAttributeValues;
7+
//! use bevy_mesh::VertexAttributeValues;
88
//!
99
//! // creating std::vec::Vec
1010
//! let buffer = vec![[0_u32; 4]; 10];
1111
//!
12-
//! // converting std::vec::Vec to bevy_render::mesh::VertexAttributeValues
12+
//! // converting std::vec::Vec to bevy_mesh::VertexAttributeValues
1313
//! let values = VertexAttributeValues::from(buffer.clone());
1414
//!
15-
//! // converting bevy_render::mesh::VertexAttributeValues to std::vec::Vec with two ways
15+
//! // converting bevy_mesh::VertexAttributeValues to std::vec::Vec with two ways
1616
//! let result_into: Vec<[u32; 4]> = values.clone().try_into().unwrap();
1717
//! let result_from: Vec<[u32; 4]> = Vec::try_from(values.clone()).unwrap();
1818
//!
@@ -24,7 +24,7 @@
2424
//! assert!(error.is_err());
2525
//! ```
2626
27-
use crate::mesh::VertexAttributeValues;
27+
use super::VertexAttributeValues;
2828
use bevy_math::{IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4};
2929
use thiserror::Error;
3030

crates/bevy_mesh/src/index.rs

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
use bevy_reflect::Reflect;
2+
use core::iter::FusedIterator;
3+
use thiserror::Error;
4+
use wgpu::IndexFormat;
5+
6+
/// A disjunction of four iterators. This is necessary to have a well-formed type for the output
7+
/// of [`Mesh::triangles`](super::Mesh::triangles), which produces iterators of four different types depending on the
8+
/// branch taken.
9+
pub(crate) enum FourIterators<A, B, C, D> {
10+
First(A),
11+
Second(B),
12+
Third(C),
13+
Fourth(D),
14+
}
15+
16+
impl<A, B, C, D, I> Iterator for FourIterators<A, B, C, D>
17+
where
18+
A: Iterator<Item = I>,
19+
B: Iterator<Item = I>,
20+
C: Iterator<Item = I>,
21+
D: Iterator<Item = I>,
22+
{
23+
type Item = I;
24+
25+
fn next(&mut self) -> Option<Self::Item> {
26+
match self {
27+
FourIterators::First(iter) => iter.next(),
28+
FourIterators::Second(iter) => iter.next(),
29+
FourIterators::Third(iter) => iter.next(),
30+
FourIterators::Fourth(iter) => iter.next(),
31+
}
32+
}
33+
}
34+
35+
/// An error that occurred while trying to invert the winding of a [`Mesh`](super::Mesh).
36+
#[derive(Debug, Error)]
37+
pub enum MeshWindingInvertError {
38+
/// This error occurs when you try to invert the winding for a mesh with [`PrimitiveTopology::PointList`](super::PrimitiveTopology::PointList).
39+
#[error("Mesh winding invertation does not work for primitive topology `PointList`")]
40+
WrongTopology,
41+
42+
/// This error occurs when you try to invert the winding for a mesh with
43+
/// * [`PrimitiveTopology::TriangleList`](super::PrimitiveTopology::TriangleList), but the indices are not in chunks of 3.
44+
/// * [`PrimitiveTopology::LineList`](super::PrimitiveTopology::LineList), but the indices are not in chunks of 2.
45+
#[error("Indices weren't in chunks according to topology")]
46+
AbruptIndicesEnd,
47+
}
48+
49+
/// An error that occurred while trying to extract a collection of triangles from a [`Mesh`](super::Mesh).
50+
#[derive(Debug, Error)]
51+
pub enum MeshTrianglesError {
52+
#[error("Source mesh does not have primitive topology TriangleList or TriangleStrip")]
53+
WrongTopology,
54+
55+
#[error("Source mesh lacks position data")]
56+
MissingPositions,
57+
58+
#[error("Source mesh position data is not Float32x3")]
59+
PositionsFormat,
60+
61+
#[error("Source mesh lacks face index data")]
62+
MissingIndices,
63+
64+
#[error("Face index data references vertices that do not exist")]
65+
BadIndices,
66+
}
67+
68+
/// An array of indices into the [`VertexAttributeValues`](super::VertexAttributeValues) for a mesh.
69+
///
70+
/// It describes the order in which the vertex attributes should be joined into faces.
71+
#[derive(Debug, Clone, Reflect)]
72+
pub enum Indices {
73+
U16(Vec<u16>),
74+
U32(Vec<u32>),
75+
}
76+
77+
impl Indices {
78+
/// Returns an iterator over the indices.
79+
pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
80+
match self {
81+
Indices::U16(vec) => IndicesIter::U16(vec.iter()),
82+
Indices::U32(vec) => IndicesIter::U32(vec.iter()),
83+
}
84+
}
85+
86+
/// Returns the number of indices.
87+
pub fn len(&self) -> usize {
88+
match self {
89+
Indices::U16(vec) => vec.len(),
90+
Indices::U32(vec) => vec.len(),
91+
}
92+
}
93+
94+
/// Returns `true` if there are no indices.
95+
pub fn is_empty(&self) -> bool {
96+
match self {
97+
Indices::U16(vec) => vec.is_empty(),
98+
Indices::U32(vec) => vec.is_empty(),
99+
}
100+
}
101+
}
102+
103+
/// An Iterator for the [`Indices`].
104+
enum IndicesIter<'a> {
105+
U16(core::slice::Iter<'a, u16>),
106+
U32(core::slice::Iter<'a, u32>),
107+
}
108+
109+
impl Iterator for IndicesIter<'_> {
110+
type Item = usize;
111+
112+
fn next(&mut self) -> Option<Self::Item> {
113+
match self {
114+
IndicesIter::U16(iter) => iter.next().map(|val| *val as usize),
115+
IndicesIter::U32(iter) => iter.next().map(|val| *val as usize),
116+
}
117+
}
118+
119+
fn size_hint(&self) -> (usize, Option<usize>) {
120+
match self {
121+
IndicesIter::U16(iter) => iter.size_hint(),
122+
IndicesIter::U32(iter) => iter.size_hint(),
123+
}
124+
}
125+
}
126+
127+
impl<'a> ExactSizeIterator for IndicesIter<'a> {}
128+
impl<'a> FusedIterator for IndicesIter<'a> {}
129+
130+
impl From<&Indices> for IndexFormat {
131+
fn from(indices: &Indices) -> Self {
132+
match indices {
133+
Indices::U16(_) => IndexFormat::Uint16,
134+
Indices::U32(_) => IndexFormat::Uint32,
135+
}
136+
}
137+
}

crates/bevy_mesh/src/lib.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// FIXME(15321): solve CI failures, then replace with `#![expect()]`.
2+
#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
3+
#![allow(unsafe_code)]
4+
5+
extern crate alloc;
6+
extern crate core;
7+
8+
mod conversions;
9+
mod index;
10+
mod mesh;
11+
mod mikktspace;
12+
pub mod morph;
13+
pub mod primitives;
14+
pub mod skinning;
15+
mod vertex;
16+
use bitflags::bitflags;
17+
pub use index::*;
18+
pub use mesh::*;
19+
pub use mikktspace::*;
20+
pub use primitives::*;
21+
pub use vertex::*;
22+
23+
bitflags! {
24+
/// Our base mesh pipeline key bits start from the highest bit and go
25+
/// downward. The PBR mesh pipeline key bits start from the lowest bit and
26+
/// go upward. This allows the PBR bits in the downstream crate `bevy_pbr`
27+
/// to coexist in the same field without any shifts.
28+
#[derive(Clone, Debug)]
29+
pub struct BaseMeshPipelineKey: u64 {
30+
const MORPH_TARGETS = 1 << (u64::BITS - 1);
31+
}
32+
}
33+
34+
impl BaseMeshPipelineKey {
35+
pub const PRIMITIVE_TOPOLOGY_MASK_BITS: u64 = 0b111;
36+
pub const PRIMITIVE_TOPOLOGY_SHIFT_BITS: u64 =
37+
(u64::BITS - 1 - Self::PRIMITIVE_TOPOLOGY_MASK_BITS.count_ones()) as u64;
38+
39+
pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
40+
let primitive_topology_bits = ((primitive_topology as u64)
41+
& Self::PRIMITIVE_TOPOLOGY_MASK_BITS)
42+
<< Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
43+
Self::from_bits_retain(primitive_topology_bits)
44+
}
45+
46+
pub fn primitive_topology(&self) -> PrimitiveTopology {
47+
let primitive_topology_bits = (self.bits() >> Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS)
48+
& Self::PRIMITIVE_TOPOLOGY_MASK_BITS;
49+
match primitive_topology_bits {
50+
x if x == PrimitiveTopology::PointList as u64 => PrimitiveTopology::PointList,
51+
x if x == PrimitiveTopology::LineList as u64 => PrimitiveTopology::LineList,
52+
x if x == PrimitiveTopology::LineStrip as u64 => PrimitiveTopology::LineStrip,
53+
x if x == PrimitiveTopology::TriangleList as u64 => PrimitiveTopology::TriangleList,
54+
x if x == PrimitiveTopology::TriangleStrip as u64 => PrimitiveTopology::TriangleStrip,
55+
_ => PrimitiveTopology::default(),
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)