fyrox_impl/scene/mesh/
surface.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Surface is a set of triangles with a single material. Such arrangement makes GPU rendering very efficient.
22//! See [`Surface`] docs for more info and usage examples.
23
24use crate::{
25    asset::{
26        io::ResourceIo,
27        loader::{BoxedLoaderFuture, LoaderPayload, ResourceLoader},
28        state::LoadError,
29        untyped::ResourceKind,
30        Resource, ResourceData,
31    },
32    core::{
33        algebra::{Matrix4, Point3, Vector2, Vector3, Vector4},
34        hash_combine,
35        log::Log,
36        math::TriangleDefinition,
37        pool::{ErasedHandle, Handle},
38        reflect::prelude::*,
39        sparse::AtomicIndex,
40        type_traits::prelude::*,
41        uuid_provider,
42        variable::InheritableVariable,
43        visitor::{Visit, VisitResult, Visitor},
44        Uuid,
45    },
46    material::{self, Material, MaterialResource, MaterialResourceExtension},
47    resource::texture::{TextureKind, TexturePixelKind, TextureResource, TextureResourceExtension},
48    scene::{
49        mesh::{
50            buffer::{
51                TriangleBuffer, VertexAttributeUsage, VertexBuffer, VertexFetchError,
52                VertexReadTrait, VertexTrait, VertexWriteTrait,
53            },
54            vertex::StaticVertex,
55        },
56        node::Node,
57    },
58    utils::raw_mesh::{RawMesh, RawMeshBuilder},
59};
60use bytemuck::{Pod, Zeroable};
61use fxhash::{FxHashMap, FxHasher};
62use fyrox_resource::manager::BuiltInResource;
63use half::f16;
64use lazy_static::lazy_static;
65use std::{
66    error::Error,
67    hash::Hasher,
68    path::{Path, PathBuf},
69    sync::Arc,
70};
71
72/// A target shape for blending.
73#[derive(Debug, Clone, Visit, Reflect, PartialEq)]
74pub struct BlendShape {
75    /// Weight of the shape.
76    #[reflect(min_value = 0.0, max_value = 100.0, step = 1.0)]
77    pub weight: f32,
78    /// A name of the shape.
79    #[reflect(read_only)]
80    pub name: String,
81}
82
83uuid_provider!(BlendShape = "fea08418-58fe-4fde-991b-36be235432bd");
84
85impl Default for BlendShape {
86    fn default() -> Self {
87        Self {
88            weight: 100.0,
89            name: Default::default(),
90        }
91    }
92}
93
94/// A container for multiple blend shapes/
95#[derive(Reflect, Debug, Clone, Default)]
96pub struct BlendShapesContainer {
97    /// A list of blend shapes.
98    pub blend_shapes: Vec<BlendShape>,
99    /// A volume texture that stores all blend shapes at once.
100    pub blend_shape_storage: Option<TextureResource>,
101}
102
103/// A set of offsets for particular vertices.
104#[derive(Clone)]
105pub struct InputBlendShapeData {
106    /// Weight of the shape.
107    pub default_weight: f32,
108    /// A name of the shape.
109    pub name: String,
110    /// An `index -> position` map. Could be empty if the blend shape does not change positions.
111    pub positions: FxHashMap<u32, Vector3<f16>>,
112    /// An `index -> normal` map. Could be empty if the blend shape does not change normals.
113    pub normals: FxHashMap<u32, Vector3<f16>>,
114    /// An `index -> tangent` map. Could be empty if the blend shape does not change tangents.
115    pub tangents: FxHashMap<u32, Vector3<f16>>,
116}
117
118impl BlendShapesContainer {
119    /// Packs all blend shapes into one volume texture.
120    pub fn from_lists(
121        base_shape: &VertexBuffer,
122        input_blend_shapes: &[InputBlendShapeData],
123    ) -> Self {
124        #[repr(C)]
125        #[derive(Default, Clone, Copy, Pod, Zeroable)]
126        struct VertexData {
127            position: Vector3<f16>,
128            normal: Vector3<f16>,
129            tangent: Vector3<f16>,
130        }
131
132        #[inline]
133        fn coord_to_index(x: usize, y: usize, z: usize, width: usize, height: usize) -> usize {
134            z * width * height + y * width + x
135        }
136
137        #[inline]
138        fn index_to_2d_coord(index: usize, width: usize) -> Vector2<usize> {
139            let y = index / width;
140            let x = index - width * y; // index % textureWidth
141            Vector2::new(x, y)
142        }
143
144        #[inline]
145        fn fetch(
146            vertices: &mut [VertexData],
147            vertex_index: usize,
148            width: u32,
149            height: u32,
150            layer: usize,
151        ) -> Option<&mut VertexData> {
152            let coord = index_to_2d_coord(vertex_index, width as usize);
153            vertices.get_mut(coord_to_index(
154                coord.x,
155                coord.y,
156                layer,
157                width as usize,
158                height as usize,
159            ))
160        }
161
162        let width = base_shape.vertex_count().min(512);
163        let height = (base_shape.vertex_count() as f32 / width as f32).ceil() as u32;
164        let depth = input_blend_shapes.len() as u32;
165
166        let mut vertex_data = vec![VertexData::default(); (width * height * depth) as usize];
167
168        for (layer, blend_shape) in input_blend_shapes.iter().enumerate() {
169            for (index, position) in blend_shape.positions.iter() {
170                if let Some(vertex) = fetch(&mut vertex_data, *index as usize, width, height, layer)
171                {
172                    vertex.position = *position;
173                }
174            }
175
176            for (index, normal) in blend_shape.normals.iter() {
177                if let Some(vertex) = fetch(&mut vertex_data, *index as usize, width, height, layer)
178                {
179                    vertex.normal = *normal;
180                }
181            }
182
183            for (index, tangent) in blend_shape.tangents.iter() {
184                if let Some(vertex) = fetch(&mut vertex_data, *index as usize, width, height, layer)
185                {
186                    vertex.tangent = *tangent;
187                }
188            }
189        }
190
191        let bytes = crate::core::transmute_vec_as_bytes::<VertexData>(vertex_data);
192
193        assert_eq!(
194            bytes.len(),
195            (width * height * depth) as usize * std::mem::size_of::<VertexData>()
196        );
197
198        Self {
199            blend_shapes: input_blend_shapes
200                .iter()
201                .map(|bs| BlendShape {
202                    weight: bs.default_weight,
203                    name: bs.name.clone(),
204                })
205                .collect(),
206            blend_shape_storage: Some(
207                TextureResource::from_bytes(
208                    TextureKind::Volume {
209                        width: width * 3,
210                        height,
211                        depth,
212                    },
213                    TexturePixelKind::RGB16F,
214                    bytes,
215                    ResourceKind::Embedded,
216                )
217                .unwrap(),
218            ),
219        }
220    }
221}
222
223/// Data source of a surface. Each surface can share same data source, this is used
224/// in instancing technique to render multiple instances of same model at different
225/// places.
226#[derive(Debug, Clone, Default, Reflect, TypeUuidProvider)]
227#[type_uuid(id = "8a23a414-e66d-4e12-9628-92c6ab49c2f0")]
228pub struct SurfaceData {
229    /// Current vertex buffer.
230    pub vertex_buffer: VertexBuffer,
231    /// Current geometry buffer.
232    pub geometry_buffer: TriangleBuffer,
233    /// A container for blend shapes.
234    pub blend_shapes_container: Option<BlendShapesContainer>,
235    #[reflect(hidden)]
236    pub(crate) cache_index: Arc<AtomicIndex>,
237}
238
239impl ResourceData for SurfaceData {
240    fn type_uuid(&self) -> Uuid {
241        <SurfaceData as fyrox_core::TypeUuidProvider>::type_uuid()
242    }
243
244    fn save(&mut self, _path: &Path) -> Result<(), Box<dyn Error>> {
245        // TODO: Add saving.
246        Ok(())
247    }
248
249    fn can_be_saved(&self) -> bool {
250        true
251    }
252}
253
254impl SurfaceData {
255    /// Creates new data source using given vertices and indices.
256    pub fn new(vertex_buffer: VertexBuffer, triangles: TriangleBuffer) -> Self {
257        Self {
258            vertex_buffer,
259            geometry_buffer: triangles,
260            blend_shapes_container: None,
261            cache_index: Arc::new(AtomicIndex::unassigned()),
262        }
263    }
264
265    /// Applies given transform for every spatial part of the data (vertex position, normal, tangent).
266    pub fn transform_geometry(&mut self, transform: &Matrix4<f32>) -> Result<(), VertexFetchError> {
267        // Discard scale by inverse and transpose given transform (M^-1)^T
268        let normal_matrix = transform.try_inverse().unwrap_or_default().transpose();
269
270        let mut vertex_buffer_mut = self.vertex_buffer.modify();
271        for mut view in vertex_buffer_mut.iter_mut() {
272            let position = view.read_3_f32(VertexAttributeUsage::Position)?;
273            view.write_3_f32(
274                VertexAttributeUsage::Position,
275                transform.transform_point(&Point3::from(position)).coords,
276            )?;
277            let normal = view.read_3_f32(VertexAttributeUsage::Normal)?;
278            view.write_3_f32(
279                VertexAttributeUsage::Normal,
280                normal_matrix.transform_vector(&normal),
281            )?;
282            let tangent = view.read_4_f32(VertexAttributeUsage::Tangent)?;
283            let new_tangent = normal_matrix.transform_vector(&tangent.xyz());
284            // Keep sign (W).
285            view.write_4_f32(
286                VertexAttributeUsage::Tangent,
287                Vector4::new(new_tangent.x, new_tangent.y, new_tangent.z, tangent.w),
288            )?;
289        }
290
291        Ok(())
292    }
293
294    /// Converts raw mesh into "renderable" mesh. It is useful to build procedural meshes. See [`RawMesh`] docs for more
295    /// info.
296    pub fn from_raw_mesh<T>(raw: RawMesh<T>) -> Self
297    where
298        T: VertexTrait,
299    {
300        Self {
301            vertex_buffer: VertexBuffer::new(raw.vertices.len(), raw.vertices).unwrap(),
302            geometry_buffer: TriangleBuffer::new(raw.triangles),
303            blend_shapes_container: Default::default(),
304            cache_index: Arc::new(AtomicIndex::unassigned()),
305        }
306    }
307
308    /// Calculates tangents of surface. Tangents are needed for correct lighting, you will get incorrect lighting if
309    /// tangents of your surface are invalid! When engine loads a mesh from "untrusted" source, it automatically calculates
310    /// tangents for you, so there is no need to call this manually in this case. However if you making your mesh
311    /// procedurally, you have to use this method! This method uses "classic" method which is described in:
312    /// "Computing Tangent Space Basis Vectors for an Arbitrary Mesh" article by Eric Lengyel.
313    pub fn calculate_tangents(&mut self) -> Result<(), VertexFetchError> {
314        let mut tan1 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];
315        let mut tan2 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];
316
317        for triangle in self.geometry_buffer.iter() {
318            let i1 = triangle[0] as usize;
319            let i2 = triangle[1] as usize;
320            let i3 = triangle[2] as usize;
321
322            let view1 = &self.vertex_buffer.get(i1).unwrap();
323            let view2 = &self.vertex_buffer.get(i2).unwrap();
324            let view3 = &self.vertex_buffer.get(i3).unwrap();
325
326            let v1 = view1.read_3_f32(VertexAttributeUsage::Position)?;
327            let v2 = view2.read_3_f32(VertexAttributeUsage::Position)?;
328            let v3 = view3.read_3_f32(VertexAttributeUsage::Position)?;
329
330            // Check for degenerated triangles
331            if v1 == v2 || v1 == v3 || v2 == v3 {
332                Log::warn(format!(
333                    "Degenerated triangle found when calculating tangents. Lighting may be \
334                    incorrect! Triangle indices: {triangle:?}. Triangle vertices: {v1} {v2} {v3}",
335                ));
336            }
337
338            let w1 = view1.read_3_f32(VertexAttributeUsage::TexCoord0)?;
339            let w2 = view2.read_3_f32(VertexAttributeUsage::TexCoord0)?;
340            let w3 = view3.read_3_f32(VertexAttributeUsage::TexCoord0)?;
341
342            let x1 = v2.x - v1.x;
343            let x2 = v3.x - v1.x;
344            let y1 = v2.y - v1.y;
345            let y2 = v3.y - v1.y;
346            let z1 = v2.z - v1.z;
347            let z2 = v3.z - v1.z;
348
349            let s1 = w2.x - w1.x;
350            let s2 = w3.x - w1.x;
351            let t1 = w2.y - w1.y;
352            let t2 = w3.y - w1.y;
353
354            let r = 1.0 / (s1 * t2 - s2 * t1);
355
356            let sdir = Vector3::new(
357                (t2 * x1 - t1 * x2) * r,
358                (t2 * y1 - t1 * y2) * r,
359                (t2 * z1 - t1 * z2) * r,
360            );
361
362            tan1[i1] += sdir;
363            tan1[i2] += sdir;
364            tan1[i3] += sdir;
365
366            let tdir = Vector3::new(
367                (s1 * x2 - s2 * x1) * r,
368                (s1 * y2 - s2 * y1) * r,
369                (s1 * z2 - s2 * z1) * r,
370            );
371            tan2[i1] += tdir;
372            tan2[i2] += tdir;
373            tan2[i3] += tdir;
374        }
375
376        let mut vertex_buffer_mut = self.vertex_buffer.modify();
377        for (mut view, (t1, t2)) in vertex_buffer_mut.iter_mut().zip(tan1.into_iter().zip(tan2)) {
378            let normal = view.read_3_f32(VertexAttributeUsage::Normal)?;
379
380            // Gram-Schmidt orthogonalize
381            let tangent = (t1 - normal.scale(normal.dot(&t1)))
382                .try_normalize(f32::EPSILON)
383                .unwrap_or_else(|| Vector3::new(0.0, 1.0, 0.0));
384            let handedness = normal.cross(&t1).dot(&t2).signum();
385            view.write_4_f32(
386                VertexAttributeUsage::Tangent,
387                Vector4::new(tangent.x, tangent.y, tangent.z, handedness),
388            )?;
389        }
390
391        Ok(())
392    }
393
394    /// Creates a quad oriented on oXY plane with unit width and height.
395    pub fn make_unit_xy_quad() -> Self {
396        let vertices = vec![
397            StaticVertex {
398                position: Vector3::default(),
399                normal: Vector3::z(),
400                tex_coord: Vector2::y(),
401                tangent: Vector4::default(),
402            },
403            StaticVertex {
404                position: Vector3::x(),
405                normal: Vector3::z(),
406                tex_coord: Vector2::new(1.0, 1.0),
407                tangent: Vector4::default(),
408            },
409            StaticVertex {
410                position: Vector3::new(1.0, 1.0, 0.0),
411                normal: Vector3::z(),
412                tex_coord: Vector2::x(),
413                tangent: Vector4::default(),
414            },
415            StaticVertex {
416                position: Vector3::y(),
417                normal: Vector3::z(),
418                tex_coord: Vector2::default(),
419                tangent: Vector4::default(),
420            },
421        ];
422
423        let triangles = vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
424
425        Self::new(
426            VertexBuffer::new(vertices.len(), vertices).unwrap(),
427            TriangleBuffer::new(triangles),
428        )
429    }
430
431    /// Creates a degenerated quad which collapsed in a point. This is very special method for sprite renderer - shader will
432    /// automatically "push" corners in correct sides so sprite will always face camera.
433    pub fn make_collapsed_xy_quad() -> Self {
434        let vertices = vec![
435            StaticVertex {
436                position: Vector3::default(),
437                normal: Vector3::z(),
438                tex_coord: Vector2::default(),
439                tangent: Vector4::default(),
440            },
441            StaticVertex {
442                position: Vector3::default(),
443                normal: Vector3::z(),
444                tex_coord: Vector2::x(),
445                tangent: Vector4::default(),
446            },
447            StaticVertex {
448                position: Vector3::default(),
449                normal: Vector3::z(),
450                tex_coord: Vector2::new(1.0, 1.0),
451                tangent: Vector4::default(),
452            },
453            StaticVertex {
454                position: Vector3::default(),
455                normal: Vector3::z(),
456                tex_coord: Vector2::y(),
457                tangent: Vector4::default(),
458            },
459        ];
460
461        let triangles = vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
462
463        Self::new(
464            VertexBuffer::new(vertices.len(), vertices).unwrap(),
465            TriangleBuffer::new(triangles),
466        )
467    }
468
469    /// Creates new quad at oXY plane with given transform.
470    pub fn make_quad(transform: &Matrix4<f32>) -> Self {
471        let vertices = vec![
472            StaticVertex {
473                position: Vector3::new(-0.5, 0.5, 0.0),
474                normal: -Vector3::z(),
475                tex_coord: Vector2::new(1.0, 1.0),
476                tangent: Vector4::default(),
477            },
478            StaticVertex {
479                position: Vector3::new(0.5, 0.5, 0.0),
480                normal: -Vector3::z(),
481                tex_coord: Vector2::new(0.0, 1.0),
482                tangent: Vector4::default(),
483            },
484            StaticVertex {
485                position: Vector3::new(0.5, -0.5, 0.0),
486                normal: -Vector3::z(),
487                tex_coord: Vector2::new(0.0, 0.0),
488                tangent: Vector4::default(),
489            },
490            StaticVertex {
491                position: Vector3::new(-0.5, -0.5, 0.0),
492                normal: -Vector3::z(),
493                tex_coord: Vector2::new(1.0, 0.0),
494                tangent: Vector4::default(),
495            },
496        ];
497
498        let mut data = Self::new(
499            VertexBuffer::new(vertices.len(), vertices).unwrap(),
500            TriangleBuffer::new(vec![
501                TriangleDefinition([0, 1, 2]),
502                TriangleDefinition([0, 2, 3]),
503            ]),
504        );
505        data.calculate_tangents().unwrap();
506        data.transform_geometry(transform).unwrap();
507        data
508    }
509
510    /// Calculates per-face normals. This method is fast, but have very poor quality, and surface will look facet.
511    pub fn calculate_normals(&mut self) -> Result<(), VertexFetchError> {
512        let mut vertex_buffer_mut = self.vertex_buffer.modify();
513        for triangle in self.geometry_buffer.iter() {
514            let ia = triangle[0] as usize;
515            let ib = triangle[1] as usize;
516            let ic = triangle[2] as usize;
517
518            let a = vertex_buffer_mut
519                .get(ia)
520                .unwrap()
521                .read_3_f32(VertexAttributeUsage::Position)?;
522            let b = vertex_buffer_mut
523                .get(ib)
524                .unwrap()
525                .read_3_f32(VertexAttributeUsage::Position)?;
526            let c = vertex_buffer_mut
527                .get(ic)
528                .unwrap()
529                .read_3_f32(VertexAttributeUsage::Position)?;
530
531            let normal = (b - a).cross(&(c - a)).normalize();
532
533            vertex_buffer_mut
534                .get_mut(ia)
535                .unwrap()
536                .write_3_f32(VertexAttributeUsage::Normal, normal)?;
537            vertex_buffer_mut
538                .get_mut(ib)
539                .unwrap()
540                .write_3_f32(VertexAttributeUsage::Normal, normal)?;
541            vertex_buffer_mut
542                .get_mut(ic)
543                .unwrap()
544                .write_3_f32(VertexAttributeUsage::Normal, normal)?;
545        }
546
547        Ok(())
548    }
549
550    /// Creates sphere of specified radius with given slices and stacks. The larger the `slices` and `stacks`, the smoother the sphere will be.
551    /// Typical values are [16..32]. The sphere is then transformed by the given transformation matrix, which could be [`Matrix4::identity`]
552    /// to not modify the sphere at all.
553    pub fn make_sphere(slices: usize, stacks: usize, r: f32, transform: &Matrix4<f32>) -> Self {
554        let mut builder = RawMeshBuilder::<StaticVertex>::new(stacks * slices, stacks * slices * 3);
555
556        let d_theta = std::f32::consts::PI / slices as f32;
557        let d_phi = 2.0 * std::f32::consts::PI / stacks as f32;
558        let d_tc_y = 1.0 / stacks as f32;
559        let d_tc_x = 1.0 / slices as f32;
560
561        for i in 0..stacks {
562            for j in 0..slices {
563                let nj = j + 1;
564                let ni = i + 1;
565
566                let k0 = r * (d_theta * i as f32).sin();
567                let k1 = (d_phi * j as f32).cos();
568                let k2 = (d_phi * j as f32).sin();
569                let k3 = r * (d_theta * i as f32).cos();
570
571                let k4 = r * (d_theta * ni as f32).sin();
572                let k5 = (d_phi * nj as f32).cos();
573                let k6 = (d_phi * nj as f32).sin();
574                let k7 = r * (d_theta * ni as f32).cos();
575
576                if i != (stacks - 1) {
577                    let v0 = Vector3::new(k0 * k1, k0 * k2, k3);
578                    let t0 = Vector2::new(d_tc_x * j as f32, d_tc_y * i as f32);
579
580                    let v1 = Vector3::new(k4 * k1, k4 * k2, k7);
581                    let t1 = Vector2::new(d_tc_x * j as f32, d_tc_y * ni as f32);
582
583                    let v2 = Vector3::new(k4 * k5, k4 * k6, k7);
584                    let t2 = Vector2::new(d_tc_x * nj as f32, d_tc_y * ni as f32);
585
586                    builder.insert(StaticVertex::from_pos_uv_normal(v0, t0, v0));
587                    builder.insert(StaticVertex::from_pos_uv_normal(v1, t1, v1));
588                    builder.insert(StaticVertex::from_pos_uv_normal(v2, t2, v2));
589                }
590
591                if i != 0 {
592                    let v0 = Vector3::new(k4 * k5, k4 * k6, k7);
593                    let t0 = Vector2::new(d_tc_x * nj as f32, d_tc_y * ni as f32);
594
595                    let v1 = Vector3::new(k0 * k5, k0 * k6, k3);
596                    let t1 = Vector2::new(d_tc_x * nj as f32, d_tc_y * i as f32);
597
598                    let v2 = Vector3::new(k0 * k1, k0 * k2, k3);
599                    let t2 = Vector2::new(d_tc_x * j as f32, d_tc_y * i as f32);
600
601                    builder.insert(StaticVertex::from_pos_uv_normal(v0, t0, v0));
602                    builder.insert(StaticVertex::from_pos_uv_normal(v1, t1, v1));
603                    builder.insert(StaticVertex::from_pos_uv_normal(v2, t2, v2));
604                }
605            }
606        }
607
608        let mut data = Self::from_raw_mesh(builder.build());
609        data.calculate_tangents().unwrap();
610        data.transform_geometry(transform).unwrap();
611        data
612    }
613
614    /// Creates vertical cone with the given amount of sides, radius, height. The larger the amount of sides, the smoother the cone
615    /// will be, typical values are [16..32]. The cone is then transformed using the given transformation matrix, which could be
616    /// [`Matrix4::identity`] to not modify the cone at all.
617    pub fn make_cone(sides: usize, r: f32, h: f32, transform: &Matrix4<f32>) -> Self {
618        let mut builder = RawMeshBuilder::<StaticVertex>::new(3 * sides, 3 * sides);
619
620        let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
621        let d_theta = 1.0 / sides as f32;
622
623        for i in 0..sides {
624            let nx0 = (d_phi * i as f32).cos();
625            let ny0 = (d_phi * i as f32).sin();
626            let nx1 = (d_phi * (i + 1) as f32).cos();
627            let ny1 = (d_phi * (i + 1) as f32).sin();
628
629            let x0 = r * nx0;
630            let z0 = r * ny0;
631            let x1 = r * nx1;
632            let z1 = r * ny1;
633            let tx0 = d_theta * i as f32;
634            let tx1 = d_theta * (i + 1) as f32;
635
636            // back cap
637            let (t_cap_y_curr, t_cap_x_curr) = (d_phi * i as f32).sin_cos();
638            let (t_cap_y_next, t_cap_x_next) = (d_phi * (i + 1) as f32).sin_cos();
639
640            let t_cap_x_curr = t_cap_x_curr * 0.5 + 0.5;
641            let t_cap_y_curr = t_cap_y_curr * 0.5 + 0.5;
642
643            let t_cap_x_next = t_cap_x_next * 0.5 + 0.5;
644            let t_cap_y_next = t_cap_y_next * 0.5 + 0.5;
645
646            builder.insert(StaticVertex::from_pos_uv_normal(
647                Vector3::new(0.0, 0.0, 0.0),
648                Vector2::new(0.5, 0.5),
649                Vector3::new(0.0, -1.0, 0.0),
650            ));
651            builder.insert(StaticVertex::from_pos_uv_normal(
652                Vector3::new(x0, 0.0, z0),
653                Vector2::new(t_cap_x_curr, t_cap_y_curr),
654                Vector3::new(0.0, -1.0, 0.0),
655            ));
656            builder.insert(StaticVertex::from_pos_uv_normal(
657                Vector3::new(x1, 0.0, z1),
658                Vector2::new(t_cap_x_next, t_cap_y_next),
659                Vector3::new(0.0, -1.0, 0.0),
660            ));
661
662            // sides
663            let tip = Vector3::new(0.0, h, 0.0);
664            let v_curr = Vector3::new(x0, 0.0, z0);
665            let v_next = Vector3::new(x1, 0.0, z1);
666            let n_next = (tip - v_next).cross(&(v_next - v_curr));
667            let n_curr = (tip - v_curr).cross(&(v_next - v_curr));
668
669            builder.insert(StaticVertex::from_pos_uv_normal(
670                tip,
671                Vector2::new(0.5, 0.0),
672                n_curr,
673            ));
674            builder.insert(StaticVertex::from_pos_uv_normal(
675                v_next,
676                Vector2::new(tx1, 1.0),
677                n_next,
678            ));
679            builder.insert(StaticVertex::from_pos_uv_normal(
680                v_curr,
681                Vector2::new(tx0, 1.0),
682                n_curr,
683            ));
684        }
685
686        let mut data = Self::from_raw_mesh(builder.build());
687        data.calculate_tangents().unwrap();
688        data.transform_geometry(transform).unwrap();
689        data
690    }
691
692    /// Creates a torus in oXY plane with the given inner and outer radii. `num_rings` defines the amount of "slices" around the Z axis of the
693    /// torus shape, `num_segments` defines the amount of segments in every slice. The larger the `num_rings` and `num_segments` are, the more
694    /// smooth the torus will be, typical values are `16..32`. Torus will be transformed using the given transformation matrix, which could be
695    /// [`Matrix4::identity`] to not modify the torus at all.
696    pub fn make_torus(
697        inner_radius: f32,
698        outer_radius: f32,
699        num_rings: usize,
700        num_segments: usize,
701        transform: &Matrix4<f32>,
702    ) -> Self {
703        let mut vertices = Vec::new();
704        for j in 0..=num_rings {
705            for i in 0..=num_segments {
706                let u = i as f32 / num_segments as f32 * std::f32::consts::TAU;
707                let v = j as f32 / num_rings as f32 * std::f32::consts::TAU;
708
709                let center = Vector3::new(inner_radius * u.cos(), inner_radius * u.sin(), 0.0);
710
711                let position = Vector3::new(
712                    (inner_radius + outer_radius * v.cos()) * u.cos(),
713                    outer_radius * v.sin(),
714                    (inner_radius + outer_radius * v.cos()) * u.sin(),
715                );
716
717                let uv = Vector2::new(i as f32 / num_segments as f32, j as f32 / num_rings as f32);
718
719                let normal = (position - center)
720                    .try_normalize(f32::EPSILON)
721                    .unwrap_or_default();
722
723                vertices.push(StaticVertex::from_pos_uv_normal(position, uv, normal));
724            }
725        }
726
727        let mut triangles = Vec::new();
728        for j in 1..=num_rings {
729            for i in 1..=num_segments {
730                let a = ((num_segments + 1) * j + i - 1) as u32;
731                let b = ((num_segments + 1) * (j - 1) + i - 1) as u32;
732                let c = ((num_segments + 1) * (j - 1) + i) as u32;
733                let d = ((num_segments + 1) * j + i) as u32;
734
735                triangles.push(TriangleDefinition([a, b, d]));
736                triangles.push(TriangleDefinition([b, c, d]));
737            }
738        }
739
740        let mut data = Self::new(
741            VertexBuffer::new(vertices.len(), vertices).unwrap(),
742            TriangleBuffer::new(triangles),
743        );
744        data.calculate_tangents().unwrap();
745        data.transform_geometry(transform).unwrap();
746        data
747    }
748
749    /// Creates vertical cylinder with the given amount of sides, radius, height and optional caps. The larger the `sides`, the smoother the cylinder
750    /// will be, typical values are [16..32]. `caps` defines whether the cylinder will have caps or not. The cylinder is transformed using the given
751    /// transformation matrix, which could be [`Matrix4::identity`] to not modify the cylinder at all.
752    pub fn make_cylinder(
753        sides: usize,
754        r: f32,
755        h: f32,
756        caps: bool,
757        transform: &Matrix4<f32>,
758    ) -> Self {
759        let mut builder = RawMeshBuilder::<StaticVertex>::new(3 * sides, 3 * sides);
760
761        let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
762        let d_theta = 1.0 / sides as f32;
763
764        for i in 0..sides {
765            let nx0 = (d_phi * i as f32).cos();
766            let ny0 = (d_phi * i as f32).sin();
767            let nx1 = (d_phi * (i + 1) as f32).cos();
768            let ny1 = (d_phi * (i + 1) as f32).sin();
769
770            let x0 = r * nx0;
771            let z0 = r * ny0;
772            let x1 = r * nx1;
773            let z1 = r * ny1;
774
775            if caps {
776                let (t_cap_y_curr, t_cap_x_curr) = (d_phi * i as f32).sin_cos();
777                let (t_cap_y_next, t_cap_x_next) = (d_phi * (i + 1) as f32).sin_cos();
778
779                let t_cap_x_curr = t_cap_x_curr * 0.5 + 0.5;
780                let t_cap_y_curr = t_cap_y_curr * 0.5 + 0.5;
781
782                let t_cap_x_next = t_cap_x_next * 0.5 + 0.5;
783                let t_cap_y_next = t_cap_y_next * 0.5 + 0.5;
784
785                // front cap
786                builder.insert(StaticVertex::from_pos_uv_normal(
787                    Vector3::new(x1, h, z1),
788                    Vector2::new(t_cap_x_next, t_cap_y_next),
789                    Vector3::new(0.0, 1.0, 0.0),
790                ));
791                builder.insert(StaticVertex::from_pos_uv_normal(
792                    Vector3::new(x0, h, z0),
793                    Vector2::new(t_cap_x_curr, t_cap_y_curr),
794                    Vector3::new(0.0, 1.0, 0.0),
795                ));
796                builder.insert(StaticVertex::from_pos_uv_normal(
797                    Vector3::new(0.0, h, 0.0),
798                    Vector2::new(0.5, 0.5),
799                    Vector3::new(0.0, 1.0, 0.0),
800                ));
801
802                // back cap
803                builder.insert(StaticVertex::from_pos_uv_normal(
804                    Vector3::new(x0, 0.0, z0),
805                    Vector2::new(t_cap_x_curr, t_cap_y_curr),
806                    Vector3::new(0.0, -1.0, 0.0),
807                ));
808                builder.insert(StaticVertex::from_pos_uv_normal(
809                    Vector3::new(x1, 0.0, z1),
810                    Vector2::new(t_cap_x_next, t_cap_y_next),
811                    Vector3::new(0.0, -1.0, 0.0),
812                ));
813                builder.insert(StaticVertex::from_pos_uv_normal(
814                    Vector3::new(0.0, 0.0, 0.0),
815                    Vector2::new(0.5, 0.5),
816                    Vector3::new(0.0, -1.0, 0.0),
817                ));
818            }
819
820            let t_side_curr = d_theta * i as f32;
821            let t_side_next = d_theta * (i + 1) as f32;
822
823            // sides
824            builder.insert(StaticVertex::from_pos_uv_normal(
825                Vector3::new(x0, 0.0, z0),
826                Vector2::new(t_side_curr, 0.0),
827                Vector3::new(x0, 0.0, z0),
828            ));
829            builder.insert(StaticVertex::from_pos_uv_normal(
830                Vector3::new(x0, h, z0),
831                Vector2::new(t_side_curr, 1.0),
832                Vector3::new(x0, 0.0, z0),
833            ));
834            builder.insert(StaticVertex::from_pos_uv_normal(
835                Vector3::new(x1, 0.0, z1),
836                Vector2::new(t_side_next, 0.0),
837                Vector3::new(x1, 0.0, z1),
838            ));
839
840            builder.insert(StaticVertex::from_pos_uv_normal(
841                Vector3::new(x1, 0.0, z1),
842                Vector2::new(t_side_next, 0.0),
843                Vector3::new(x1, 0.0, z1),
844            ));
845            builder.insert(StaticVertex::from_pos_uv_normal(
846                Vector3::new(x0, h, z0),
847                Vector2::new(t_side_curr, 1.0),
848                Vector3::new(x0, 0.0, z0),
849            ));
850            builder.insert(StaticVertex::from_pos_uv_normal(
851                Vector3::new(x1, h, z1),
852                Vector2::new(t_side_next, 1.0),
853                Vector3::new(x1, 0.0, z1),
854            ));
855        }
856
857        let mut data = Self::from_raw_mesh(builder.build());
858        data.calculate_tangents().unwrap();
859        data.transform_geometry(transform).unwrap();
860        data
861    }
862
863    /// Creates unit cube with the given transform, which could be [`Matrix4::identity`] to not modify the cube at all and leave it unit.
864    pub fn make_cube(transform: Matrix4<f32>) -> Self {
865        let vertices = vec![
866            // Front
867            StaticVertex {
868                position: Vector3::new(-0.5, -0.5, 0.5),
869                normal: Vector3::z(),
870                tex_coord: Vector2::default(),
871                tangent: Vector4::default(),
872            },
873            StaticVertex {
874                position: Vector3::new(-0.5, 0.5, 0.5),
875                normal: Vector3::z(),
876                tex_coord: Vector2::y(),
877                tangent: Vector4::default(),
878            },
879            StaticVertex {
880                position: Vector3::new(0.5, 0.5, 0.5),
881                normal: Vector3::z(),
882                tex_coord: Vector2::new(1.0, 1.0),
883                tangent: Vector4::default(),
884            },
885            StaticVertex {
886                position: Vector3::new(0.5, -0.5, 0.5),
887                normal: Vector3::z(),
888                tex_coord: Vector2::x(),
889                tangent: Vector4::default(),
890            },
891            // Back
892            StaticVertex {
893                position: Vector3::new(-0.5, -0.5, -0.5),
894                normal: -Vector3::z(),
895                tex_coord: Vector2::default(),
896                tangent: Vector4::default(),
897            },
898            StaticVertex {
899                position: Vector3::new(-0.5, 0.5, -0.5),
900                normal: -Vector3::z(),
901                tex_coord: Vector2::y(),
902                tangent: Vector4::default(),
903            },
904            StaticVertex {
905                position: Vector3::new(0.5, 0.5, -0.5),
906                normal: -Vector3::z(),
907                tex_coord: Vector2::new(1.0, 1.0),
908                tangent: Vector4::default(),
909            },
910            StaticVertex {
911                position: Vector3::new(0.5, -0.5, -0.5),
912                normal: -Vector3::z(),
913                tex_coord: Vector2::x(),
914                tangent: Vector4::default(),
915            },
916            // Left
917            StaticVertex {
918                position: Vector3::new(-0.5, -0.5, -0.5),
919                normal: -Vector3::x(),
920                tex_coord: Vector2::default(),
921                tangent: Vector4::default(),
922            },
923            StaticVertex {
924                position: Vector3::new(-0.5, 0.5, -0.5),
925                normal: -Vector3::x(),
926                tex_coord: Vector2::y(),
927                tangent: Vector4::default(),
928            },
929            StaticVertex {
930                position: Vector3::new(-0.5, 0.5, 0.5),
931                normal: -Vector3::x(),
932                tex_coord: Vector2::new(1.0, 1.0),
933                tangent: Vector4::default(),
934            },
935            StaticVertex {
936                position: Vector3::new(-0.5, -0.5, 0.5),
937                normal: -Vector3::x(),
938                tex_coord: Vector2::x(),
939                tangent: Vector4::default(),
940            },
941            // Right
942            StaticVertex {
943                position: Vector3::new(0.5, -0.5, -0.5),
944                normal: Vector3::x(),
945                tex_coord: Vector2::default(),
946                tangent: Vector4::default(),
947            },
948            StaticVertex {
949                position: Vector3::new(0.5, 0.5, -0.5),
950                normal: Vector3::x(),
951                tex_coord: Vector2::y(),
952                tangent: Vector4::default(),
953            },
954            StaticVertex {
955                position: Vector3::new(0.5, 0.5, 0.5),
956                normal: Vector3::x(),
957                tex_coord: Vector2::new(1.0, 1.0),
958                tangent: Vector4::default(),
959            },
960            StaticVertex {
961                position: Vector3::new(0.5, -0.5, 0.5),
962                normal: Vector3::x(),
963                tex_coord: Vector2::x(),
964                tangent: Vector4::default(),
965            },
966            // Top
967            StaticVertex {
968                position: Vector3::new(-0.5, 0.5, 0.5),
969                normal: Vector3::y(),
970                tex_coord: Vector2::default(),
971                tangent: Vector4::default(),
972            },
973            StaticVertex {
974                position: Vector3::new(-0.5, 0.5, -0.5),
975                normal: Vector3::y(),
976                tex_coord: Vector2::y(),
977                tangent: Vector4::default(),
978            },
979            StaticVertex {
980                position: Vector3::new(0.5, 0.5, -0.5),
981                normal: Vector3::y(),
982                tex_coord: Vector2::new(1.0, 1.0),
983                tangent: Vector4::default(),
984            },
985            StaticVertex {
986                position: Vector3::new(0.5, 0.5, 0.5),
987                normal: Vector3::y(),
988                tex_coord: Vector2::x(),
989                tangent: Vector4::default(),
990            },
991            // Bottom
992            StaticVertex {
993                position: Vector3::new(-0.5, -0.5, 0.5),
994                normal: -Vector3::y(),
995                tex_coord: Vector2::default(),
996                tangent: Vector4::default(),
997            },
998            StaticVertex {
999                position: Vector3::new(-0.5, -0.5, -0.5),
1000                normal: -Vector3::y(),
1001                tex_coord: Vector2::y(),
1002                tangent: Vector4::default(),
1003            },
1004            StaticVertex {
1005                position: Vector3::new(0.5, -0.5, -0.5),
1006                normal: -Vector3::y(),
1007                tex_coord: Vector2::new(1.0, 1.0),
1008                tangent: Vector4::default(),
1009            },
1010            StaticVertex {
1011                position: Vector3::new(0.5, -0.5, 0.5),
1012                normal: -Vector3::y(),
1013                tex_coord: Vector2::x(),
1014                tangent: Vector4::default(),
1015            },
1016        ];
1017
1018        let triangles = vec![
1019            TriangleDefinition([2, 1, 0]),
1020            TriangleDefinition([3, 2, 0]),
1021            TriangleDefinition([4, 5, 6]),
1022            TriangleDefinition([4, 6, 7]),
1023            TriangleDefinition([10, 9, 8]),
1024            TriangleDefinition([11, 10, 8]),
1025            TriangleDefinition([12, 13, 14]),
1026            TriangleDefinition([12, 14, 15]),
1027            TriangleDefinition([18, 17, 16]),
1028            TriangleDefinition([19, 18, 16]),
1029            TriangleDefinition([20, 21, 22]),
1030            TriangleDefinition([20, 22, 23]),
1031        ];
1032
1033        let mut data = Self::new(
1034            VertexBuffer::new(vertices.len(), vertices).unwrap(),
1035            TriangleBuffer::new(triangles),
1036        );
1037        data.calculate_tangents().unwrap();
1038        data.transform_geometry(&transform).unwrap();
1039        data
1040    }
1041
1042    /// Calculates hash based on the contents of the surface shared data. This could be time-consuming
1043    /// if there's a lot of vertices or indices.
1044    pub fn content_hash(&self) -> u64 {
1045        hash_combine(
1046            self.geometry_buffer.content_hash(),
1047            self.vertex_buffer.content_hash(),
1048        )
1049    }
1050
1051    /// Clears both vertex and index buffers.
1052    pub fn clear(&mut self) {
1053        self.geometry_buffer.modify().clear();
1054        self.vertex_buffer.modify().clear();
1055    }
1056}
1057
1058impl Visit for SurfaceData {
1059    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1060        let mut region = visitor.enter_region(name)?;
1061
1062        self.vertex_buffer.visit("VertexBuffer", &mut region)?;
1063        self.geometry_buffer.visit("GeometryBuffer", &mut region)?;
1064
1065        Ok(())
1066    }
1067}
1068
1069/// Vertex weight is a pair of (bone; weight) that affects vertex.
1070#[derive(Copy, Clone, PartialEq, Debug)]
1071pub struct VertexWeight {
1072    /// Exact weight value in [0; 1] range
1073    pub value: f32,
1074    /// Handle to an entity that affects this vertex. It has double meaning
1075    /// relative to context:
1076    /// 1. When converting fbx model to engine node it points to FbxModel
1077    ///    that control this vertex via sub deformer.
1078    /// 2. After conversion is done, on resolve stage it points to a Node
1079    ///    in a scene to which converter put all the nodes.
1080    pub effector: ErasedHandle,
1081}
1082
1083impl Default for VertexWeight {
1084    fn default() -> Self {
1085        Self {
1086            value: 0.0,
1087            effector: ErasedHandle::none(),
1088        }
1089    }
1090}
1091
1092/// Weight set contains up to four pairs of (bone; weight).
1093#[derive(Copy, Clone, Debug, PartialEq, Default)]
1094pub struct VertexWeightSet {
1095    weights: [VertexWeight; 4],
1096    count: usize,
1097}
1098
1099impl VertexWeightSet {
1100    /// Pushes new weight in the set and returns true if vertex was pushed,
1101    /// false - otherwise.
1102    pub fn push(&mut self, weight: VertexWeight) -> bool {
1103        if self.count < self.weights.len() {
1104            self.weights[self.count] = weight;
1105            self.count += 1;
1106            true
1107        } else {
1108            false
1109        }
1110    }
1111
1112    /// Returns exact amount of weights in the set.
1113    pub fn len(&self) -> usize {
1114        self.count
1115    }
1116
1117    /// Returns true if set is empty.
1118    pub fn is_empty(&self) -> bool {
1119        self.count == 0
1120    }
1121
1122    /// Returns shared iterator.
1123    pub fn iter(&self) -> std::slice::Iter<VertexWeight> {
1124        self.weights[0..self.count].iter()
1125    }
1126
1127    /// Returns mutable iterator.
1128    pub fn iter_mut(&mut self) -> std::slice::IterMut<VertexWeight> {
1129        self.weights[0..self.count].iter_mut()
1130    }
1131
1132    /// Normalizes weights in the set so they form unit 4-d vector. This method is useful
1133    /// when mesh has more than 4 weights per vertex. Engine supports only 4 weights per
1134    /// vertex so when there are more than 4 weights, first four weights may not give sum
1135    /// equal to 1.0, we must fix that to prevent weirdly looking results.
1136    pub fn normalize(&mut self) {
1137        let len = self.iter().fold(0.0, |qs, w| qs + w.value * w.value).sqrt();
1138        if len >= f32::EPSILON {
1139            let k = 1.0 / len;
1140            for w in self.iter_mut() {
1141                w.value *= k;
1142            }
1143        }
1144    }
1145}
1146
1147/// Surface shared data is a vertex and index buffer that can be shared across multiple objects. This is
1148/// very useful memory optimization - you create a single data storage for a surface and then share it
1149/// with any instance count you want. Memory usage does not increase with instance count in this case.
1150pub type SurfaceResource = Resource<SurfaceData>;
1151
1152/// A trait with extension methods for surface resource.
1153pub trait SurfaceResourceExtension {
1154    /// Creates a full copy of the internals of the data and creates a new surface resource of it.
1155    fn deep_clone(&self) -> Self;
1156}
1157
1158impl SurfaceResourceExtension for SurfaceResource {
1159    fn deep_clone(&self) -> Self {
1160        Self::new_ok(self.kind(), self.data_ref().clone())
1161    }
1162}
1163
1164/// Surface is a set of triangles with a single material. Such arrangement makes GPU rendering very efficient.
1165///
1166/// Surfaces can use the same data source across many instances, this is a memory optimization for being able to
1167/// re-use data when you need to draw the same mesh in many places. It guarantees, that the data will be in single
1168/// instance on your GPU.
1169///
1170/// ## Examples
1171///
1172/// ```rust
1173/// # use fyrox_impl::{
1174/// #     core::{
1175/// #         algebra::{Vector2, Vector3, Vector4},
1176/// #         math::TriangleDefinition,
1177/// #     },
1178/// #     scene::mesh::{
1179/// #         buffer::{TriangleBuffer, VertexBuffer},
1180/// #         surface::{Surface, SurfaceBuilder, SurfaceData, SurfaceResource},
1181/// #         vertex::StaticVertex,
1182/// #     },
1183/// # };
1184/// use fyrox_resource::untyped::ResourceKind;
1185/// fn create_triangle_surface() -> Surface {
1186///     let vertex_buffer = VertexBuffer::new(
1187///         3,
1188///         vec![
1189///             StaticVertex {
1190///                 position: Vector3::new(0.0, 0.0, 0.0),
1191///                 tex_coord: Vector2::new(0.0, 0.0),
1192///                 normal: Vector3::new(0.0, 0.0, 1.0),
1193///                 tangent: Vector4::new(1.0, 0.0, 0.0, 1.0),
1194///             },
1195///             StaticVertex {
1196///                 position: Vector3::new(0.0, 1.0, 0.0),
1197///                 tex_coord: Vector2::new(0.0, 1.0),
1198///                 normal: Vector3::new(0.0, 0.0, 1.0),
1199///                 tangent: Vector4::new(1.0, 0.0, 0.0, 1.0),
1200///             },
1201///             StaticVertex {
1202///                 position: Vector3::new(1.0, 1.0, 0.0),
1203///                 tex_coord: Vector2::new(1.0, 1.0),
1204///                 normal: Vector3::new(0.0, 0.0, 1.0),
1205///                 tangent: Vector4::new(1.0, 0.0, 0.0, 1.0),
1206///             },
1207///         ],
1208///     )
1209///     .unwrap();
1210///
1211///     let triangle_buffer = TriangleBuffer::new(vec![TriangleDefinition([0, 1, 2])]);
1212///
1213///     let data = SurfaceData::new(vertex_buffer, triangle_buffer);
1214///
1215///     SurfaceBuilder::new(SurfaceResource::new_ok(ResourceKind::Embedded, data)).build()
1216/// }
1217/// ```
1218///
1219/// This code crates a simple triangle in oXY plane with clockwise winding with normal facing towards the screen.
1220/// To learn more about vertex and triangle buffers, see [`VertexBuffer`] and [`TriangleBuffer`] docs respectively.
1221///
1222/// Usually, there's no need to create surfaces on per-vertex basis, you can use on of the pre-made methods of
1223/// [`SurfaceData`] to create complex 3D shapes:
1224///
1225/// ```rust
1226/// # use fyrox_impl::{
1227/// #     core::algebra::Matrix4,
1228/// #     scene::mesh::surface::{Surface, SurfaceBuilder, SurfaceData, SurfaceResource},
1229/// # };
1230/// use fyrox_resource::untyped::ResourceKind;
1231/// fn create_cone_surface() -> Surface {
1232///     SurfaceBuilder::new(SurfaceResource::new_ok(ResourceKind::Embedded, SurfaceData::make_cone(
1233///         16,
1234///         1.0,
1235///         2.0,
1236///         &Matrix4::identity(),
1237///     )))
1238///     .build()
1239/// }
1240/// ```
1241///
1242/// This code snippet creates a cone surface instance, check the docs for [`SurfaceData`] for more info about built-in
1243/// methods.
1244#[derive(Debug, Reflect, PartialEq)]
1245pub struct Surface {
1246    pub(crate) data: InheritableVariable<SurfaceResource>,
1247
1248    pub(crate) material: InheritableVariable<MaterialResource>,
1249
1250    /// Array of handles to scene nodes which are used as bones.
1251    pub bones: InheritableVariable<Vec<Handle<Node>>>,
1252
1253    #[reflect(
1254        description = "If true, then the current material will become a unique instance when cloning the surface.\
1255        Could be useful if you need to have unique materials per on every instance. Keep in mind that this option \
1256        might affect performance!"
1257    )]
1258    unique_material: InheritableVariable<bool>,
1259
1260    // Temporal array for FBX conversion needs, it holds skinning data (weight + bone handle)
1261    // and will be used to fill actual bone indices and weight in vertices that will be
1262    // sent to GPU. The idea is very simple: GPU needs to know only indices of matrices of
1263    // bones so we can use `bones` array as reference to get those indices. This could be done
1264    // like so: iterate over all vertices and weight data and calculate index of node handle that
1265    // associated with vertex in `bones` array and store it as bone index in vertex.
1266    #[reflect(hidden)]
1267    pub(crate) vertex_weights: Vec<VertexWeightSet>,
1268}
1269
1270uuid_provider!(Surface = "485caf12-4e7d-4b1a-b6bd-0681fd92f789");
1271
1272impl Clone for Surface {
1273    fn clone(&self) -> Self {
1274        Self {
1275            data: self.data.clone(),
1276            material: if *self.unique_material {
1277                // Create unique instance.
1278                self.material.deep_copy_as_embedded().into()
1279            } else {
1280                // Share the material.
1281                self.material.clone()
1282            },
1283            bones: self.bones.clone(),
1284            unique_material: self.unique_material.clone(),
1285            vertex_weights: self.vertex_weights.clone(),
1286        }
1287    }
1288}
1289
1290impl Visit for Surface {
1291    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
1292        let mut region = visitor.enter_region(name)?;
1293
1294        // Backward compatibility.
1295        if region.is_reading() {
1296            if let Some(material) = material::visit_old_material(&mut region) {
1297                self.material = material.into();
1298            } else {
1299                self.material.visit("Material", &mut region)?;
1300            }
1301        } else {
1302            self.material.visit("Material", &mut region)?;
1303        }
1304
1305        self.data.visit("Data", &mut region)?;
1306        self.bones.visit("Bones", &mut region)?;
1307        let _ = self.unique_material.visit("UniqueMaterial", &mut region); // Backward compatibility.
1308
1309        Ok(())
1310    }
1311}
1312
1313impl Default for Surface {
1314    fn default() -> Self {
1315        Self {
1316            data: SurfaceResource::new_ok(
1317                ResourceKind::Embedded,
1318                SurfaceData::make_cube(Matrix4::identity()),
1319            )
1320            .into(),
1321            material: MaterialResource::new_ok(Default::default(), Material::standard()).into(),
1322            vertex_weights: Default::default(),
1323            bones: Default::default(),
1324            unique_material: Default::default(),
1325        }
1326    }
1327}
1328
1329impl Surface {
1330    /// Creates new surface instance with given data and without any texture.
1331    #[inline]
1332    pub fn new(data: SurfaceResource) -> Self {
1333        Self {
1334            data: data.into(),
1335            ..Default::default()
1336        }
1337    }
1338
1339    /// Calculates material id.
1340    pub fn material_id(&self) -> u64 {
1341        self.material.key()
1342    }
1343
1344    /// Calculates batch id.
1345    pub fn batch_id(&self) -> u64 {
1346        let mut hasher = FxHasher::default();
1347        hasher.write_u64(self.material_id());
1348        hasher.write_u64(self.data.key());
1349        hasher.finish()
1350    }
1351
1352    /// Returns current data used by surface.
1353    #[inline]
1354    pub fn data(&self) -> SurfaceResource {
1355        (*self.data).clone()
1356    }
1357
1358    /// Returns current data used by surface.
1359    #[inline]
1360    pub fn data_ref(&self) -> &SurfaceResource {
1361        &self.data
1362    }
1363
1364    /// Returns current material of the surface.
1365    pub fn material(&self) -> &MaterialResource {
1366        &self.material
1367    }
1368
1369    /// Sets new material for the surface.
1370    pub fn set_material(&mut self, material: MaterialResource) {
1371        self.material.set_value_and_mark_modified(material);
1372    }
1373
1374    /// Returns list of bones that affects the surface.
1375    #[inline]
1376    pub fn bones(&self) -> &[Handle<Node>] {
1377        &self.bones
1378    }
1379
1380    /// Returns true if the material will be a unique instance when cloning the surface.
1381    pub fn is_unique_material(&self) -> bool {
1382        *self.unique_material
1383    }
1384
1385    /// Defines whether the material will be a unique instance when cloning the surface.
1386    pub fn set_unique_material(&mut self, unique: bool) {
1387        self.unique_material.set_value_and_mark_modified(unique);
1388    }
1389}
1390
1391/// Surface builder allows you to create surfaces in declarative manner.
1392pub struct SurfaceBuilder {
1393    data: SurfaceResource,
1394    material: Option<MaterialResource>,
1395    bones: Vec<Handle<Node>>,
1396    unique_material: bool,
1397}
1398
1399impl SurfaceBuilder {
1400    /// Creates new builder instance with given data and no textures or bones.
1401    pub fn new(data: SurfaceResource) -> Self {
1402        Self {
1403            data,
1404            material: None,
1405            bones: Default::default(),
1406            unique_material: false,
1407        }
1408    }
1409
1410    /// Sets desired diffuse texture.
1411    pub fn with_material(mut self, material: MaterialResource) -> Self {
1412        self.material = Some(material);
1413        self
1414    }
1415
1416    /// Sets desired bones array. Make sure your vertices has valid indices of bones!
1417    pub fn with_bones(mut self, bones: Vec<Handle<Node>>) -> Self {
1418        self.bones = bones;
1419        self
1420    }
1421
1422    /// Sets whether the material will be a unique instance when cloning the surface.
1423    pub fn with_unique_material(mut self, unique: bool) -> Self {
1424        self.unique_material = unique;
1425        self
1426    }
1427
1428    /// Creates new instance of surface.
1429    pub fn build(self) -> Surface {
1430        Surface {
1431            data: self.data.into(),
1432            material: self
1433                .material
1434                .unwrap_or_else(|| {
1435                    MaterialResource::new_ok(Default::default(), Material::standard())
1436                })
1437                .into(),
1438            vertex_weights: Default::default(),
1439            bones: self.bones.into(),
1440            unique_material: self.unique_material.into(),
1441        }
1442    }
1443}
1444
1445/// Default surface resource loader.
1446pub struct SurfaceDataLoader {}
1447
1448impl ResourceLoader for SurfaceDataLoader {
1449    fn extensions(&self) -> &[&str] {
1450        &["surface"]
1451    }
1452
1453    fn data_type_uuid(&self) -> Uuid {
1454        <SurfaceData as TypeUuidProvider>::type_uuid()
1455    }
1456
1457    fn load(&self, path: PathBuf, io: Arc<dyn ResourceIo>) -> BoxedLoaderFuture {
1458        Box::pin(async move {
1459            let io = io.as_ref();
1460
1461            let data = io.load_file(&path).await.map_err(LoadError::new)?;
1462            let mut visitor = Visitor::load_from_memory(&data).map_err(LoadError::new)?;
1463            let mut surface_data = SurfaceData::default();
1464            surface_data
1465                .visit("SurfaceData", &mut visitor)
1466                .map_err(LoadError::new)?;
1467            Ok(LoaderPayload::new(surface_data))
1468        })
1469    }
1470}
1471
1472lazy_static! {
1473    /// Cube surface resource.
1474    pub static ref CUBE: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1475        SurfaceResource::new_ok(
1476            "__CubeSurface".into(),
1477            SurfaceData::make_cube(Matrix4::identity()),
1478        )
1479    );
1480
1481    /// Quad surface resource.
1482    pub static ref QUAD: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1483        SurfaceResource::new_ok(
1484            "__QuadSurface".into(),
1485            SurfaceData::make_quad(&Matrix4::identity()),
1486        )
1487    );
1488
1489    /// Cylinder surface resource.
1490    pub static ref CYLINDER: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1491        SurfaceResource::new_ok(
1492            "__CylinderSurface".into(),
1493            SurfaceData::make_cylinder(32, 1.0, 1.0, true, &Matrix4::identity()),
1494        )
1495    );
1496
1497    /// Sphere surface resource.
1498    pub static ref SPHERE: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1499        SurfaceResource::new_ok(
1500            "__SphereSurface".into(),
1501            SurfaceData::make_sphere(32, 32, 1.0, &Matrix4::identity()),
1502        )
1503    );
1504
1505    /// Cone surface resource.
1506    pub static ref CONE: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1507        SurfaceResource::new_ok(
1508            "__ConeSurface".into(),
1509            SurfaceData::make_cone(32, 1.0, 1.0, &Matrix4::identity()),
1510        )
1511    );
1512
1513    /// Torus surface resource.
1514    pub static ref TORUS: BuiltInResource<SurfaceData> = BuiltInResource::new_no_source(
1515        SurfaceResource::new_ok(
1516            "__TorusSurface".into(),
1517            SurfaceData::make_torus(1.0, 0.25,32, 32,  &Matrix4::identity()),
1518        )
1519    );
1520}