fyrox_impl/scene/mesh/
surface.rs

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