@@ -5,13 +5,19 @@ use bevy_asset::{
5
5
} ;
6
6
use bevy_math:: Vec3 ;
7
7
use bevy_reflect:: TypePath ;
8
+ use bevy_tasks:: block_on;
8
9
use bytemuck:: { Pod , Zeroable } ;
9
10
use lz4_flex:: frame:: { FrameDecoder , FrameEncoder } ;
10
- use serde:: { Deserialize , Serialize } ;
11
- use std:: { io:: Cursor , sync:: Arc } ;
11
+ use std:: {
12
+ io:: { Read , Write } ,
13
+ sync:: Arc ,
14
+ } ;
15
+
16
+ /// Unique identifier for the [`MeshletMesh`] asset format.
17
+ const MESHLET_MESH_ASSET_MAGIC : u64 = 1717551717668 ;
12
18
13
19
/// The current version of the [`MeshletMesh`] asset format.
14
- pub const MESHLET_MESH_ASSET_VERSION : u64 = 0 ;
20
+ pub const MESHLET_MESH_ASSET_VERSION : u64 = 1 ;
15
21
16
22
/// A mesh that has been pre-processed into multiple small clusters of triangles called meshlets.
17
23
///
@@ -27,24 +33,24 @@ pub const MESHLET_MESH_ASSET_VERSION: u64 = 0;
27
33
/// * Limited control over [`bevy_render::render_resource::RenderPipelineDescriptor`] attributes.
28
34
///
29
35
/// See also [`super::MaterialMeshletMeshBundle`] and [`super::MeshletPlugin`].
30
- #[ derive( Asset , TypePath , Serialize , Deserialize , Clone ) ]
36
+ #[ derive( Asset , TypePath , Clone ) ]
31
37
pub struct MeshletMesh {
32
38
/// The total amount of triangles summed across all LOD 0 meshlets in the mesh.
33
- pub worst_case_meshlet_triangles : u64 ,
39
+ pub ( crate ) worst_case_meshlet_triangles : u64 ,
34
40
/// Raw vertex data bytes for the overall mesh.
35
- pub vertex_data : Arc < [ u8 ] > ,
41
+ pub ( crate ) vertex_data : Arc < [ u8 ] > ,
36
42
/// Indices into `vertex_data`.
37
- pub vertex_ids : Arc < [ u32 ] > ,
43
+ pub ( crate ) vertex_ids : Arc < [ u32 ] > ,
38
44
/// Indices into `vertex_ids`.
39
- pub indices : Arc < [ u8 ] > ,
45
+ pub ( crate ) indices : Arc < [ u8 ] > ,
40
46
/// The list of meshlets making up this mesh.
41
- pub meshlets : Arc < [ Meshlet ] > ,
47
+ pub ( crate ) meshlets : Arc < [ Meshlet ] > ,
42
48
/// Spherical bounding volumes.
43
- pub bounding_spheres : Arc < [ MeshletBoundingSpheres ] > ,
49
+ pub ( crate ) bounding_spheres : Arc < [ MeshletBoundingSpheres ] > ,
44
50
}
45
51
46
52
/// A single meshlet within a [`MeshletMesh`].
47
- #[ derive( Serialize , Deserialize , Copy , Clone , Pod , Zeroable ) ]
53
+ #[ derive( Copy , Clone , Pod , Zeroable ) ]
48
54
#[ repr( C ) ]
49
55
pub struct Meshlet {
50
56
/// The offset within the parent mesh's [`MeshletMesh::vertex_ids`] buffer where the indices for this meshlet begin.
@@ -56,7 +62,7 @@ pub struct Meshlet {
56
62
}
57
63
58
64
/// Bounding spheres used for culling and choosing level of detail for a [`Meshlet`].
59
- #[ derive( Serialize , Deserialize , Copy , Clone , Pod , Zeroable ) ]
65
+ #[ derive( Copy , Clone , Pod , Zeroable ) ]
60
66
#[ repr( C ) ]
61
67
pub struct MeshletBoundingSpheres {
62
68
/// The bounding sphere used for frustum and occlusion culling for this meshlet.
@@ -68,84 +74,162 @@ pub struct MeshletBoundingSpheres {
68
74
}
69
75
70
76
/// A spherical bounding volume used for a [`Meshlet`].
71
- #[ derive( Serialize , Deserialize , Copy , Clone , Pod , Zeroable ) ]
77
+ #[ derive( Copy , Clone , Pod , Zeroable ) ]
72
78
#[ repr( C ) ]
73
79
pub struct MeshletBoundingSphere {
74
80
pub center : Vec3 ,
75
81
pub radius : f32 ,
76
82
}
77
83
78
84
/// An [`AssetLoader`] and [`AssetSaver`] for `.meshlet_mesh` [`MeshletMesh`] assets.
79
- pub struct MeshletMeshSaverLoad ;
85
+ pub struct MeshletMeshSaverLoader ;
80
86
81
- impl AssetLoader for MeshletMeshSaverLoad {
87
+ impl AssetSaver for MeshletMeshSaverLoader {
82
88
type Asset = MeshletMesh ;
83
89
type Settings = ( ) ;
90
+ type OutputLoader = Self ;
84
91
type Error = MeshletMeshSaveOrLoadError ;
85
92
86
- async fn load < ' a > (
93
+ async fn save < ' a > (
87
94
& ' a self ,
88
- reader : & ' a mut dyn Reader ,
89
- _settings : & ' a Self :: Settings ,
90
- _load_context : & ' a mut LoadContext < ' _ > ,
91
- ) -> Result < Self :: Asset , Self :: Error > {
92
- let version = read_u64 ( reader ) . await ? ;
93
- if version != MESHLET_MESH_ASSET_VERSION {
94
- return Err ( MeshletMeshSaveOrLoadError :: WrongVersion { found : version } ) ;
95
- }
95
+ writer : & ' a mut Writer ,
96
+ asset : SavedAsset < ' a , MeshletMesh > ,
97
+ _settings : & ' a ( ) ,
98
+ ) -> Result < ( ) , MeshletMeshSaveOrLoadError > {
99
+ // Write asset magic number
100
+ writer
101
+ . write_all ( & MESHLET_MESH_ASSET_MAGIC . to_le_bytes ( ) )
102
+ . await ? ;
96
103
97
- let mut bytes = Vec :: new ( ) ;
98
- reader. read_to_end ( & mut bytes) . await ?;
99
- let asset = bincode:: deserialize_from ( FrameDecoder :: new ( Cursor :: new ( bytes) ) ) ?;
104
+ // Write asset version
105
+ writer
106
+ . write_all ( & MESHLET_MESH_ASSET_VERSION . to_le_bytes ( ) )
107
+ . await ?;
100
108
101
- Ok ( asset)
102
- }
109
+ // Compress and write asset data
110
+ writer
111
+ . write_all ( & asset. worst_case_meshlet_triangles . to_le_bytes ( ) )
112
+ . await ?;
113
+ let mut writer = FrameEncoder :: new ( AsyncWriteSyncAdapter ( writer) ) ;
114
+ write_slice ( & asset. vertex_data , & mut writer) ?;
115
+ write_slice ( & asset. vertex_ids , & mut writer) ?;
116
+ write_slice ( & asset. indices , & mut writer) ?;
117
+ write_slice ( & asset. meshlets , & mut writer) ?;
118
+ write_slice ( & asset. bounding_spheres , & mut writer) ?;
119
+ writer. finish ( ) ?;
103
120
104
- fn extensions ( & self ) -> & [ & str ] {
105
- & [ "meshlet_mesh" ]
121
+ Ok ( ( ) )
106
122
}
107
123
}
108
124
109
- impl AssetSaver for MeshletMeshSaverLoad {
125
+ impl AssetLoader for MeshletMeshSaverLoader {
110
126
type Asset = MeshletMesh ;
111
127
type Settings = ( ) ;
112
- type OutputLoader = Self ;
113
128
type Error = MeshletMeshSaveOrLoadError ;
114
129
115
- async fn save < ' a > (
130
+ async fn load < ' a > (
116
131
& ' a self ,
117
- writer : & ' a mut Writer ,
118
- asset : SavedAsset < ' a , Self :: Asset > ,
119
- _settings : & ' a Self :: Settings ,
120
- ) -> Result < ( ) , Self :: Error > {
121
- writer
122
- . write_all ( & MESHLET_MESH_ASSET_VERSION . to_le_bytes ( ) )
123
- . await ?;
132
+ reader : & ' a mut dyn Reader ,
133
+ _settings : & ' a ( ) ,
134
+ _load_context : & ' a mut LoadContext < ' _ > ,
135
+ ) -> Result < MeshletMesh , MeshletMeshSaveOrLoadError > {
136
+ // Load and check magic number
137
+ let magic = async_read_u64 ( reader) . await ?;
138
+ if magic != MESHLET_MESH_ASSET_MAGIC {
139
+ return Err ( MeshletMeshSaveOrLoadError :: WrongFileType ) ;
140
+ }
124
141
125
- let mut bytes = Vec :: new ( ) ;
126
- let mut sync_writer = FrameEncoder :: new ( & mut bytes ) ;
127
- bincode :: serialize_into ( & mut sync_writer , asset . get ( ) ) ? ;
128
- sync_writer . finish ( ) ? ;
129
- writer . write_all ( & bytes ) . await ? ;
142
+ // Load and check asset version
143
+ let version = async_read_u64 ( reader ) . await ? ;
144
+ if version != MESHLET_MESH_ASSET_VERSION {
145
+ return Err ( MeshletMeshSaveOrLoadError :: WrongVersion { found : version } ) ;
146
+ }
130
147
131
- Ok ( ( ) )
148
+ // Load and decompress asset data
149
+ let worst_case_meshlet_triangles = async_read_u64 ( reader) . await ?;
150
+ let reader = & mut FrameDecoder :: new ( AsyncReadSyncAdapter ( reader) ) ;
151
+ let vertex_data = read_slice ( reader) ?;
152
+ let vertex_ids = read_slice ( reader) ?;
153
+ let indices = read_slice ( reader) ?;
154
+ let meshlets = read_slice ( reader) ?;
155
+ let bounding_spheres = read_slice ( reader) ?;
156
+
157
+ Ok ( MeshletMesh {
158
+ worst_case_meshlet_triangles,
159
+ vertex_data,
160
+ vertex_ids,
161
+ indices,
162
+ meshlets,
163
+ bounding_spheres,
164
+ } )
165
+ }
166
+
167
+ fn extensions ( & self ) -> & [ & str ] {
168
+ & [ "meshlet_mesh" ]
132
169
}
133
170
}
134
171
135
172
#[ derive( thiserror:: Error , Debug ) ]
136
173
pub enum MeshletMeshSaveOrLoadError {
174
+ #[ error( "file was not a MeshletMesh asset" ) ]
175
+ WrongFileType ,
137
176
#[ error( "expected asset version {MESHLET_MESH_ASSET_VERSION} but found version {found}" ) ]
138
177
WrongVersion { found : u64 } ,
139
- #[ error( "failed to serialize or deserialize asset data" ) ]
140
- SerializationOrDeserialization ( #[ from] bincode:: Error ) ,
141
178
#[ error( "failed to compress or decompress asset data" ) ]
142
179
CompressionOrDecompression ( #[ from] lz4_flex:: frame:: Error ) ,
143
180
#[ error( "failed to read or write asset data" ) ]
144
181
Io ( #[ from] std:: io:: Error ) ,
145
182
}
146
183
147
- async fn read_u64 ( reader : & mut dyn Reader ) -> Result < u64 , bincode :: Error > {
184
+ async fn async_read_u64 ( reader : & mut dyn Reader ) -> Result < u64 , std :: io :: Error > {
148
185
let mut bytes = [ 0u8 ; 8 ] ;
149
186
reader. read_exact ( & mut bytes) . await ?;
150
187
Ok ( u64:: from_le_bytes ( bytes) )
151
188
}
189
+
190
+ fn read_u64 ( reader : & mut dyn Read ) -> Result < u64 , std:: io:: Error > {
191
+ let mut bytes = [ 0u8 ; 8 ] ;
192
+ reader. read_exact ( & mut bytes) ?;
193
+ Ok ( u64:: from_le_bytes ( bytes) )
194
+ }
195
+
196
+ fn write_slice < T : Pod > (
197
+ field : & [ T ] ,
198
+ writer : & mut dyn Write ,
199
+ ) -> Result < ( ) , MeshletMeshSaveOrLoadError > {
200
+ writer. write_all ( & ( field. len ( ) as u64 ) . to_le_bytes ( ) ) ?;
201
+ writer. write_all ( bytemuck:: cast_slice ( field) ) ?;
202
+ Ok ( ( ) )
203
+ }
204
+
205
+ fn read_slice < T : Pod > ( reader : & mut dyn Read ) -> Result < Arc < [ T ] > , std:: io:: Error > {
206
+ let len = read_u64 ( reader) ? as usize ;
207
+
208
+ let mut data: Arc < [ T ] > = std:: iter:: repeat_with ( T :: zeroed) . take ( len) . collect ( ) ;
209
+ let slice = Arc :: get_mut ( & mut data) . unwrap ( ) ;
210
+ reader. read_exact ( bytemuck:: cast_slice_mut ( slice) ) ?;
211
+
212
+ Ok ( data)
213
+ }
214
+
215
+ // TODO: Use async for everything and get rid of this adapter
216
+ struct AsyncWriteSyncAdapter < ' a > ( & ' a mut Writer ) ;
217
+
218
+ impl Write for AsyncWriteSyncAdapter < ' _ > {
219
+ fn write ( & mut self , buf : & [ u8 ] ) -> std:: io:: Result < usize > {
220
+ block_on ( self . 0 . write ( buf) )
221
+ }
222
+
223
+ fn flush ( & mut self ) -> std:: io:: Result < ( ) > {
224
+ block_on ( self . 0 . flush ( ) )
225
+ }
226
+ }
227
+
228
+ // TODO: Use async for everything and get rid of this adapter
229
+ struct AsyncReadSyncAdapter < ' a > ( & ' a mut dyn Reader ) ;
230
+
231
+ impl Read for AsyncReadSyncAdapter < ' _ > {
232
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
233
+ block_on ( self . 0 . read ( buf) )
234
+ }
235
+ }
0 commit comments