1use crate::{
6 command::{EncoderCommon, Graphics, QueueId, RenderPassEncoder, Supports},
7 core::cast_cow,
8 factory::{BufferState, Factory, UploadError},
9 memory::{Data, Upload, Write},
10 resource::{Buffer, BufferInfo, Escape},
11 AsVertex, VertexFormat,
12};
13use rendy_core::hal::adapter::PhysicalDevice;
14use std::{borrow::Cow, mem::size_of};
15
16#[derive(Debug)]
18pub struct VertexBufferLayout {
19 offset: u64,
20 format: VertexFormat,
21}
22
23#[derive(Debug)]
25pub struct IndexBuffer<B: rendy_core::hal::Backend> {
26 buffer: Escape<Buffer<B>>,
27 index_type: rendy_core::hal::IndexType,
28}
29
30#[derive(Debug)]
32pub enum Indices<'a> {
33 None,
35
36 U16(Cow<'a, [u16]>),
38
39 U32(Cow<'a, [u32]>),
41}
42
43impl From<Vec<u16>> for Indices<'static> {
44 fn from(vec: Vec<u16>) -> Self {
45 Indices::U16(vec.into())
46 }
47}
48
49impl<'a> From<&'a [u16]> for Indices<'a> {
50 fn from(slice: &'a [u16]) -> Self {
51 Indices::U16(slice.into())
52 }
53}
54
55impl<'a> From<Cow<'a, [u16]>> for Indices<'a> {
56 fn from(cow: Cow<'a, [u16]>) -> Self {
57 Indices::U16(cow)
58 }
59}
60
61impl From<Vec<u32>> for Indices<'static> {
62 fn from(vec: Vec<u32>) -> Self {
63 Indices::U32(vec.into())
64 }
65}
66
67impl<'a> From<&'a [u32]> for Indices<'a> {
68 fn from(slice: &'a [u32]) -> Self {
69 Indices::U32(slice.into())
70 }
71}
72
73impl<'a> From<Cow<'a, [u32]>> for Indices<'a> {
74 fn from(cow: Cow<'a, [u32]>) -> Self {
75 Indices::U32(cow)
76 }
77}
78
79#[derive(Clone, Debug)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct MeshBuilder<'a> {
83 #[cfg_attr(feature = "serde", serde(borrow))]
84 vertices: smallvec::SmallVec<[RawVertices<'a>; 16]>,
85 #[cfg_attr(feature = "serde", serde(borrow))]
86 indices: Option<RawIndices<'a>>,
87 prim: rendy_core::hal::pso::Primitive,
88}
89
90#[derive(Clone, Debug)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92struct RawVertices<'a> {
93 #[cfg_attr(feature = "serde", serde(with = "serde_bytes", borrow))]
94 vertices: Cow<'a, [u8]>,
95 format: VertexFormat,
96}
97
98#[derive(Clone, Debug)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100struct RawIndices<'a> {
101 #[cfg_attr(feature = "serde", serde(with = "serde_bytes", borrow))]
102 indices: Cow<'a, [u8]>,
103 index_type: rendy_core::hal::IndexType,
104}
105
106fn index_stride(index_type: rendy_core::hal::IndexType) -> usize {
107 match index_type {
108 rendy_core::hal::IndexType::U16 => size_of::<u16>(),
109 rendy_core::hal::IndexType::U32 => size_of::<u32>(),
110 }
111}
112
113impl<'a> MeshBuilder<'a> {
114 pub fn new() -> Self {
116 MeshBuilder {
117 vertices: smallvec::SmallVec::new(),
118 indices: None,
119 prim: rendy_core::hal::pso::Primitive::TriangleList,
120 }
121 }
122
123 pub fn into_owned(self) -> MeshBuilder<'static> {
126 MeshBuilder {
127 vertices: self
128 .vertices
129 .into_iter()
130 .map(|v| RawVertices {
131 vertices: Cow::Owned(v.vertices.into_owned()),
132 format: v.format,
133 })
134 .collect(),
135 indices: self.indices.map(|i| RawIndices {
136 indices: Cow::Owned(i.indices.into_owned()),
137 index_type: i.index_type,
138 }),
139 prim: self.prim,
140 }
141 }
142
143 pub fn with_indices<I>(mut self, indices: I) -> Self
145 where
146 I: Into<Indices<'a>>,
147 {
148 self.set_indices(indices);
149 self
150 }
151
152 pub fn set_indices<I>(&mut self, indices: I) -> &mut Self
154 where
155 I: Into<Indices<'a>>,
156 {
157 self.indices = match indices.into() {
158 Indices::None => None,
159 Indices::U16(i) => Some(RawIndices {
160 indices: cast_cow(i),
161 index_type: rendy_core::hal::IndexType::U16,
162 }),
163 Indices::U32(i) => Some(RawIndices {
164 indices: cast_cow(i),
165 index_type: rendy_core::hal::IndexType::U32,
166 }),
167 };
168 self
169 }
170
171 pub fn with_vertices<V, D>(mut self, vertices: D) -> Self
173 where
174 V: AsVertex + 'a,
175 D: Into<Cow<'a, [V]>>,
176 {
177 self.add_vertices(vertices);
178 self
179 }
180
181 pub fn add_vertices<V, D>(&mut self, vertices: D) -> &mut Self
183 where
184 V: AsVertex + 'a,
185 D: Into<Cow<'a, [V]>>,
186 {
187 self.vertices.push(RawVertices {
188 vertices: cast_cow(vertices.into()),
189 format: V::vertex(),
190 });
191 self
192 }
193
194 pub fn with_prim_type(mut self, prim: rendy_core::hal::pso::Primitive) -> Self {
198 self.prim = prim;
199 self
200 }
201
202 pub fn set_prim_type(&mut self, prim: rendy_core::hal::pso::Primitive) -> &mut Self {
206 self.prim = prim;
207 self
208 }
209
210 pub fn build<B>(&self, queue: QueueId, factory: &Factory<B>) -> Result<Mesh<B>, UploadError>
218 where
219 B: rendy_core::hal::Backend,
220 {
221 let align = factory.physical().limits().non_coherent_atom_size;
222 let mut len = self
223 .vertices
224 .iter()
225 .map(|v| v.vertices.len() as u32 / v.format.stride)
226 .min()
227 .unwrap_or(0);
228
229 let buffer_size = self
230 .vertices
231 .iter()
232 .map(|v| (v.format.stride * len) as usize)
233 .sum();
234
235 let aligned_size = align_by(align, buffer_size) as u64;
236
237 let mut staging = factory
238 .create_buffer(
239 BufferInfo {
240 size: aligned_size,
241 usage: rendy_core::hal::buffer::Usage::TRANSFER_SRC,
242 },
243 Upload,
244 )
245 .map_err(UploadError::Create)?;
246
247 let mut buffer = factory
248 .create_buffer(
249 BufferInfo {
250 size: buffer_size as _,
251 usage: rendy_core::hal::buffer::Usage::VERTEX
252 | rendy_core::hal::buffer::Usage::TRANSFER_DST,
253 },
254 Data,
255 )
256 .map_err(UploadError::Create)?;
257
258 let mut mapped = staging
259 .map(factory, 0..aligned_size)
260 .map_err(UploadError::Map)?;
261 let mut writer =
262 unsafe { mapped.write(factory, 0..aligned_size) }.map_err(UploadError::Map)?;
263 let staging_slice = unsafe { writer.slice() };
264
265 let mut offset = 0usize;
266 let mut vertex_layouts: Vec<_> = self
267 .vertices
268 .iter()
269 .map(|RawVertices { vertices, format }| {
270 let size = (format.stride * len) as usize;
271 staging_slice[offset..offset + size].copy_from_slice(&vertices[0..size]);
272 let this_offset = offset as u64;
273 offset += size;
274 VertexBufferLayout {
275 offset: this_offset,
276 format: format.clone(),
277 }
278 })
279 .collect();
280
281 drop(staging_slice);
282 drop(writer);
283 drop(mapped);
284
285 vertex_layouts.sort_unstable_by(|a, b| a.format.cmp(&b.format));
286
287 let index_buffer = match self.indices {
288 None => None,
289 Some(RawIndices {
290 ref indices,
291 index_type,
292 }) => {
293 len = (indices.len() / index_stride(index_type)) as u32;
294 let mut buffer = factory
295 .create_buffer(
296 BufferInfo {
297 size: indices.len() as _,
298 usage: rendy_core::hal::buffer::Usage::INDEX
299 | rendy_core::hal::buffer::Usage::TRANSFER_DST,
300 },
301 Data,
302 )
303 .map_err(UploadError::Create)?;
304 unsafe {
305 factory.upload_buffer(
307 &mut buffer,
308 0,
309 &indices,
310 None,
311 BufferState::new(queue)
312 .with_access(rendy_core::hal::buffer::Access::INDEX_BUFFER_READ)
313 .with_stage(rendy_core::hal::pso::PipelineStage::VERTEX_INPUT),
314 )?;
315 }
316
317 Some(IndexBuffer { buffer, index_type })
318 }
319 };
320
321 unsafe {
322 factory
323 .upload_from_staging_buffer(
324 &mut buffer,
325 0,
326 staging,
327 None,
328 BufferState::new(queue)
329 .with_access(rendy_core::hal::buffer::Access::VERTEX_BUFFER_READ)
330 .with_stage(rendy_core::hal::pso::PipelineStage::VERTEX_INPUT),
331 )
332 .map_err(UploadError::Upload)?;
333 }
334
335 Ok(Mesh {
336 vertex_layouts,
337 index_buffer,
338 vertex_buffer: buffer,
339 prim: self.prim,
340 len,
341 })
342 }
343}
344
345fn align_by(align: usize, value: usize) -> usize {
346 ((value + align - 1) / align) * align
347}
348
349#[derive(Debug)]
352pub struct Mesh<B: rendy_core::hal::Backend> {
353 vertex_buffer: Escape<Buffer<B>>,
354 vertex_layouts: Vec<VertexBufferLayout>,
355 index_buffer: Option<IndexBuffer<B>>,
356 prim: rendy_core::hal::pso::Primitive,
357 len: u32,
358}
359
360impl<B> Mesh<B>
361where
362 B: rendy_core::hal::Backend,
363{
364 pub fn builder<'a>() -> MeshBuilder<'a> {
366 MeshBuilder::new()
367 }
368
369 pub fn primitive(&self) -> rendy_core::hal::pso::Primitive {
371 self.prim
372 }
373
374 pub fn len(&self) -> u32 {
380 self.len
381 }
382
383 fn get_vertex_iter<'a>(
384 &'a self,
385 formats: &[VertexFormat],
386 ) -> Result<impl IntoIterator<Item = (&'a B::Buffer, u64)>, Incompatible> {
387 debug_assert!(is_slice_sorted(formats), "Formats: {:#?}", formats);
388 debug_assert!(is_slice_sorted_by_key(&self.vertex_layouts, |l| &l.format));
389
390 let mut vertex = smallvec::SmallVec::<[_; 16]>::new();
391
392 let mut next = 0;
393 for format in formats {
394 if let Some(index) = find_compatible_buffer(&self.vertex_layouts[next..], format) {
395 next += index;
396 vertex.push(self.vertex_layouts[next].offset);
397 } else {
398 return Err(Incompatible {
400 not_found: format.clone(),
401 in_formats: self
402 .vertex_layouts
403 .iter()
404 .map(|l| l.format.clone())
405 .collect(),
406 });
407 }
408 }
409
410 let buffer = self.vertex_buffer.raw();
411 Ok(vertex.into_iter().map(move |offset| (buffer, offset)))
412 }
413
414 pub fn bind<C>(
416 &self,
417 first_binding: u32,
418 formats: &[VertexFormat],
419 encoder: &mut EncoderCommon<'_, B, C>,
420 ) -> Result<u32, Incompatible>
421 where
422 C: Supports<Graphics>,
423 {
424 let vertex_iter = self.get_vertex_iter(formats)?;
425 match self.index_buffer.as_ref() {
426 Some(index_buffer) => unsafe {
427 encoder.bind_index_buffer(index_buffer.buffer.raw(), 0, index_buffer.index_type);
428 encoder.bind_vertex_buffers(first_binding, vertex_iter);
429 },
430 None => unsafe {
431 encoder.bind_vertex_buffers(first_binding, vertex_iter);
432 },
433 }
434
435 Ok(self.len)
436 }
437
438 pub fn bind_and_draw(
440 &self,
441 first_binding: u32,
442 formats: &[VertexFormat],
443 instance_range: std::ops::Range<u32>,
444 encoder: &mut RenderPassEncoder<'_, B>,
445 ) -> Result<u32, Incompatible> {
446 let vertex_iter = self.get_vertex_iter(formats)?;
447 unsafe {
448 match self.index_buffer.as_ref() {
449 Some(index_buffer) => {
450 encoder.bind_index_buffer(
451 index_buffer.buffer.raw(),
452 0,
453 index_buffer.index_type,
454 );
455 encoder.bind_vertex_buffers(first_binding, vertex_iter);
456 encoder.draw_indexed(0..self.len, 0, instance_range);
457 }
458 None => {
459 encoder.bind_vertex_buffers(first_binding, vertex_iter);
460 encoder.draw(0..self.len, instance_range);
461 }
462 }
463 }
464
465 Ok(self.len)
466 }
467}
468
469#[derive(Clone, Debug, PartialEq, Eq)]
471pub struct Incompatible {
472 pub not_found: VertexFormat,
474 pub in_formats: Vec<VertexFormat>,
476}
477
478impl std::fmt::Display for Incompatible {
479 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
480 write!(
481 f,
482 "Vertex format {:?} is not compatible with any of {:?}.",
483 self.not_found, self.in_formats
484 )
485 }
486}
487impl std::error::Error for Incompatible {}
488
489fn find_compatible_buffer(
491 vertex_layouts: &[VertexBufferLayout],
492 format: &VertexFormat,
493) -> Option<usize> {
494 debug_assert!(is_slice_sorted(&*format.attributes));
495 for (i, layout) in vertex_layouts.iter().enumerate() {
496 debug_assert!(is_slice_sorted(&*layout.format.attributes));
497 if is_compatible(&layout.format, format) {
498 return Some(i);
499 }
500 }
501 None
502}
503
504fn is_compatible(left: &VertexFormat, right: &VertexFormat) -> bool {
507 if left.stride != right.stride {
508 return false;
509 }
510
511 let mut skip = 0;
513 right.attributes.iter().all(|r| {
514 left.attributes[skip..]
515 .iter()
516 .position(|l| l == r)
517 .map_or(false, |p| {
518 skip += p;
519 true
520 })
521 })
522}
523
524fn is_slice_sorted<T: Ord>(slice: &[T]) -> bool {
526 is_slice_sorted_by_key(slice, |i| i)
527}
528
529fn is_slice_sorted_by_key<'a, T, K: Ord>(slice: &'a [T], f: impl Fn(&'a T) -> K) -> bool {
531 if let Some((first, slice)) = slice.split_first() {
532 let mut cmp = f(first);
533 for item in slice {
534 let item = f(item);
535 if cmp > item {
536 return false;
537 }
538 cmp = item;
539 }
540 }
541 true
542}
543
544impl<'a, A> From<Vec<A>> for MeshBuilder<'a>
545where
546 A: AsVertex + 'a,
547{
548 fn from(vertices: Vec<A>) -> Self {
549 MeshBuilder::new().with_vertices(vertices)
550 }
551}
552
553macro_rules! impl_builder_from_vec {
554 ($($from:ident),*) => {
555 impl<'a, $($from,)*> From<($(Vec<$from>,)*)> for MeshBuilder<'a>
556 where
557 $($from: AsVertex + 'a,)*
558 {
559 fn from(vertices: ($(Vec<$from>,)*)) -> Self {
560 #[allow(unused_mut)]
561 let mut builder = MeshBuilder::new();
562 #[allow(non_snake_case)]
563 let ($($from,)*) = vertices;
564 $(builder.add_vertices($from);)*
565 builder
566 }
567 }
568
569 impl_builder_from_vec!(@ $($from),*);
570 };
571 (@) => {};
572 (@ $head:ident $(,$tail:ident)*) => {
573 impl_builder_from_vec!($($tail),*);
574 };
575}
576
577impl_builder_from_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);