Skip to main content

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