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