gloss_renderer/components/
mesh_cpu_comps.rs

1//! These represent CPU components which you usually add to entities when you
2//! spawn them.
3
4extern crate nalgebra as na;
5// use burn::backend::ndarray::NdArrayDevice;
6// use burn::backend::candle::CandleDevice;
7// use burn::backend::Candle;
8use gloss_img::DynImage;
9use gloss_utils::{
10    io::FileLoader,
11    tensor::{DynamicTensorFloat2D, DynamicTensorInt2D},
12};
13use image::ImageReader;
14use na::DMatrix;
15use std::io::{BufReader, Cursor, Read, Seek};
16// use burn::backend::{Candle, NdArray, Wgpu};
17
18/// Component that modifications to the config
19#[derive(Clone)]
20pub struct ConfigChanges {
21    pub new_distance_fade_center: na::Point3<f32>,
22}
23
24/// Defines the color type an entity which is displayed as a point cloud
25#[derive(Debug, Clone, Copy, PartialEq)]
26pub enum PointColorType {
27    Solid = 0,
28    PerVert,
29}
30
31/// Defines the color type an entity which is displayed as a point cloud
32#[derive(Debug, Clone, Copy, PartialEq)]
33pub enum LineColorType {
34    Solid = 0,
35    PerVert,
36}
37
38/// Defines the color type an entity which is displayed as a mesh
39#[derive(Debug, Clone, Copy, PartialEq)]
40pub enum MeshColorType {
41    Solid = 0,
42    PerVert,
43    Texture,
44    UV,
45    Normal,
46    NormalViewCoords,
47}
48
49/// Component for visualization options of lines
50#[derive(Clone)]
51#[allow(clippy::struct_excessive_bools)]
52pub struct VisLines {
53    pub show_lines: bool,
54    pub line_color: na::Vector4<f32>,
55    pub line_width: f32,
56    pub color_type: LineColorType,
57    pub zbuffer: bool,
58    pub antialias_edges: bool,
59    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
60    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
61    // component manually then we shouldn't override his VisMesh.colortype.
62    pub added_automatically: bool,
63}
64/// Component for visualization options of wireframe
65#[derive(Clone)]
66pub struct VisWireframe {
67    pub show_wireframe: bool,
68    pub wire_color: na::Vector4<f32>,
69    pub wire_width: f32,
70    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
71    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
72    // component manually then we shouldn't override his VisMesh.colortype.
73    pub added_automatically: bool,
74}
75/// Component for visualization options of normals
76#[derive(Clone)]
77pub struct VisNormals {
78    pub show_normals: bool,
79    pub normals_color: na::Vector4<f32>,
80    pub normals_width: f32,
81    pub normals_scale: f32, //the scale of the arrows for the normal.
82    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
83    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
84    // component manually then we shouldn't override his VisMesh.colortype.
85    pub added_automatically: bool,
86}
87/// Component for visualization options of point clouds
88#[derive(Clone)]
89#[allow(clippy::struct_excessive_bools)]
90pub struct VisPoints {
91    pub show_points: bool,
92    pub show_points_indices: bool,
93    pub point_color: na::Vector4<f32>,
94    pub point_size: f32,
95    pub is_point_size_in_world_space: bool,
96    pub color_type: PointColorType,
97    pub zbuffer: bool,
98    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
99    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
100    // component manually then we shouldn't override his VisMesh.colortype.
101    pub added_automatically: bool,
102}
103/// Component for visualization options of meshes
104#[derive(Clone)]
105pub struct VisMesh {
106    pub show_mesh: bool,
107    pub solid_color: na::Vector4<f32>,
108    pub metalness: f32,
109    pub perceptual_roughness: f32,
110    pub roughness_black_lvl: f32,
111    pub uv_scale: f32,
112    pub opacity: f32,
113    pub needs_sss: bool,
114    pub color_type: MeshColorType,
115    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
116    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
117    // component manually then we shouldn't override his VisMesh.colortype.
118    pub added_automatically: bool,
119}
120/// Component for visualization options of meshes
121#[derive(Clone)]
122pub struct VisOutline {
123    pub show_outline: bool,
124    pub outline_color: na::Vector4<f32>,
125    pub outline_width: f32,
126    //if this components was added automatically by the renderer this will be set to true. This is useful to know since when we upload textures to
127    // gpu the vis_mesh.color_type will be set to Texture but this should happen ONLY if the VisMesh was added automatically. If the used adds this
128    // component manually then we shouldn't override his VisMesh.colortype.
129    pub added_automatically: bool,
130}
131//implementations of default vis options
132impl Default for VisLines {
133    fn default() -> VisLines {
134        VisLines {
135            show_lines: false,
136            line_color: na::Vector4::<f32>::new(1.0, 0.1, 0.1, 1.0),
137            line_width: 1.0,
138            color_type: LineColorType::Solid,
139            zbuffer: true,
140            antialias_edges: false,
141            added_automatically: false,
142        }
143    }
144}
145impl Default for VisWireframe {
146    fn default() -> VisWireframe {
147        VisWireframe {
148            show_wireframe: false,
149            wire_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
150            wire_width: 1.0,
151            added_automatically: false,
152        }
153    }
154}
155impl Default for VisNormals {
156    fn default() -> VisNormals {
157        VisNormals {
158            show_normals: false,
159            normals_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
160            normals_width: 1.0,
161            normals_scale: 1.0,
162            added_automatically: false,
163        }
164    }
165}
166impl Default for VisPoints {
167    fn default() -> VisPoints {
168        VisPoints {
169            show_points: false,
170            show_points_indices: false,
171            point_color: na::Vector4::<f32>::new(245.0 / 255.0, 175.0 / 255.0, 110.0 / 255.0, 1.0),
172            point_size: 1.0,
173            is_point_size_in_world_space: false,
174            color_type: PointColorType::Solid,
175            zbuffer: true,
176            added_automatically: false,
177        }
178    }
179}
180impl Default for VisMesh {
181    fn default() -> VisMesh {
182        VisMesh {
183            show_mesh: true,
184            solid_color: na::Vector4::<f32>::new(1.0, 206.0 / 255.0, 143.0 / 255.0, 1.0),
185            metalness: 0.0,
186            perceptual_roughness: 0.5,
187            roughness_black_lvl: 0.0,
188            uv_scale: 1.0,
189            opacity: 1.0,
190            needs_sss: false,
191            color_type: MeshColorType::Solid,
192            added_automatically: false,
193        }
194    }
195}
196impl Default for VisOutline {
197    fn default() -> VisOutline {
198        VisOutline {
199            show_outline: false,
200            outline_color: na::Vector4::<f32>::new(0.29, 0.82, 0.73, 1.0), // Blue-green default color
201            outline_width: 4.0,
202            added_automatically: false,
203        }
204    }
205}
206
207/// Component that transforms from object coordinates to world. Usually added
208/// automatically but you can also add it yourself.
209#[derive(Clone)]
210pub struct ModelMatrix(pub na::SimilarityMatrix3<f32>); //transform from object coordinates to world corresponds to TfWorldObj
211                                                        // pub struct ModelMatrix(pub na::Affine3<f32>); //transform from object
212                                                        // coordinates to world corresponds to TfWorldObj
213impl Default for ModelMatrix {
214    fn default() -> ModelMatrix {
215        ModelMatrix(na::SimilarityMatrix3::<f32>::identity())
216    }
217}
218impl ModelMatrix {
219    #[must_use]
220    pub fn with_translation(self, t: &na::Vector3<f32>) -> Self {
221        let mut mat = self;
222        mat.0.append_translation_mut(&na::Translation3::new(t[0], t[1], t[2]));
223        mat
224    }
225    #[must_use]
226    pub fn with_rotation_rot3(self, r: &na::Rotation3<f32>) -> Self {
227        let mut mat = self;
228        mat.0.append_rotation_mut(r);
229        mat
230    }
231    #[must_use]
232    pub fn with_rotation_axis_angle(self, v: &na::Vector3<f32>) -> Self {
233        let mut mat = self;
234        mat.0
235            .append_rotation_mut(&na::Rotation3::from_axis_angle(&na::UnitVector3::<f32>::new_normalize(*v), v.norm()));
236        mat
237    }
238    #[must_use]
239    pub fn with_rotation_euler(self, e: &na::Vector3<f32>) -> Self {
240        let mut mat = self;
241        mat.0.append_rotation_mut(&na::Rotation3::from_euler_angles(e.x, e.y, e.z));
242        mat
243    }
244}
245
246/// Component that represents a track of camera extrinsics - num frames x 16
247#[derive(Clone, Debug)]
248pub struct CamTrack(pub DMatrix<f32>);
249
250#[derive(Clone, Debug)]
251pub struct Verts(pub DynamicTensorFloat2D);
252
253/// Component that represents a matrix of vertex positions for the first vertex
254/// of an edge
255#[derive(Clone, Debug)]
256pub struct EdgesV1(pub DynamicTensorFloat2D);
257/// Component that represents a matrix of vertex positions for the second vertex
258/// of an edge
259#[derive(Clone, Debug)]
260pub struct EdgesV2(pub DynamicTensorFloat2D);
261
262/// Component that represents a matrix of face indices for rendering a triangle
263/// mesh
264// #[derive(Clone)]
265// pub struct Faces(pub DMatrix<u32>);
266#[derive(Clone)]
267pub struct Faces(pub DynamicTensorInt2D);
268
269/// Component that represents a matrix of edges as Nx2 where each row is the
270/// start idx and end idx of an edge which indexes into [``Verts``]
271#[derive(Clone, Debug)]
272pub struct Edges(pub DynamicTensorInt2D);
273
274/// Component that represents UV coordinates
275#[derive(Clone)]
276pub struct UVs(pub DynamicTensorFloat2D);
277// / Component that represents the scale of the uv coordinates. Increasing it
278// will tile the texture on the mesh. #[derive(Clone)]
279// pub struct UvScale(pub f32);
280
281/// Component that represents normal vectors
282#[derive(Clone)]
283pub struct Normals(pub DynamicTensorFloat2D);
284
285/// Component that represents tangents
286#[derive(Clone)]
287pub struct Tangents(pub DynamicTensorFloat2D);
288
289/// Component that represents per vertex colors
290#[derive(Clone)]
291pub struct Colors(pub DynamicTensorFloat2D);
292
293#[derive(Clone)]
294#[allow(clippy::struct_excessive_bools)]
295pub struct ImgConfig {
296    pub keep_on_cpu: bool,
297    pub fast_upload: bool, //fast upload uses the staging memory of wgpu but potentially uses more memory
298    pub generate_mipmaps: bool,
299    pub mipmap_generation_cpu: bool,
300}
301impl Default for ImgConfig {
302    fn default() -> Self {
303        Self {
304            keep_on_cpu: true,
305            fast_upload: true,
306            generate_mipmaps: true,
307            mipmap_generation_cpu: false,
308        }
309    }
310}
311
312/// A generic Img that has a path and img
313/// Concrete images like [``DiffuseImg``] will contain the generic img
314#[derive(Clone)]
315pub struct GenericImg {
316    pub path: Option<String>,
317    pub cpu_img: Option<DynImage>, //keep it as an option so we can drop it and release the memory
318    pub config: ImgConfig,
319}
320impl GenericImg {
321    /// # Panics
322    /// Will panic if the path cannot be opened.
323    pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
324        let cpu_img = Some(ImageReader::open(path).unwrap().decode().unwrap());
325
326        Self {
327            path: Some(path.to_string()),
328            cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
329            config: config.clone(),
330        }
331    }
332
333    /// # Panics
334    /// Will panic if the path cannot be opened.
335    pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
336        let reader = ImageReader::new(BufReader::new(FileLoader::open(path).await))
337            .with_guessed_format()
338            .expect("Cursor io never fails");
339
340        let cpu_img = Some(reader.decode().unwrap());
341
342        Self {
343            path: Some(path.to_string()),
344            cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
345            config: config.clone(),
346        }
347    }
348
349    /// # Panics
350    /// Will panic if the img cannot be processed and decoded.
351    pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
352        Self::new_from_reader(Cursor::new(buf), config)
353    }
354
355    /// # Panics
356    /// Will panic if the img cannot be processed and decoded.
357    pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
358        let reader_img = ImageReader::new(BufReader::new(reader))
359            .with_guessed_format()
360            .expect("Format for image should be something known and valid");
361
362        let cpu_img = Some(reader_img.decode().unwrap());
363
364        Self {
365            path: None,
366            cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
367            config: config.clone(),
368        }
369    }
370
371    pub fn img_ref(&self) -> &DynImage {
372        self.cpu_img.as_ref().unwrap()
373    }
374
375    pub fn img_ref_mut(&mut self) -> &mut DynImage {
376        self.cpu_img.as_mut().unwrap()
377    }
378}
379
380/// Component which represents a diffuse img.
381#[derive(Clone)]
382pub struct DiffuseImg {
383    pub generic_img: GenericImg,
384}
385
386impl DiffuseImg {
387    pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
388        let generic_img = GenericImg::new_from_path(path, config);
389        Self { generic_img }
390    }
391
392    pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
393        let generic_img = GenericImg::new_from_path_async(path, config).await;
394        Self { generic_img }
395    }
396
397    pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
398        let generic_img = GenericImg::new_from_buf(buf, config);
399        Self { generic_img }
400    }
401
402    pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
403        let generic_img = GenericImg::new_from_reader(reader, config);
404        Self { generic_img }
405    }
406}
407
408/// Component which represents a normal img.
409#[derive(Clone)]
410pub struct NormalImg {
411    pub generic_img: GenericImg,
412}
413
414impl NormalImg {
415    pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
416        let generic_img = GenericImg::new_from_path(path, config);
417        Self { generic_img }
418    }
419
420    pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
421        let generic_img = GenericImg::new_from_path_async(path, config).await;
422        Self { generic_img }
423    }
424
425    pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
426        let generic_img = GenericImg::new_from_buf(buf, config);
427        Self { generic_img }
428    }
429
430    pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
431        let generic_img = GenericImg::new_from_reader(reader, config);
432        Self { generic_img }
433    }
434}
435
436/// Component which represents a metalness img.
437pub struct MetalnessImg {
438    pub generic_img: GenericImg,
439}
440impl MetalnessImg {
441    pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
442        let generic_img = GenericImg::new_from_path(path, config);
443        Self { generic_img }
444    }
445
446    pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
447        let generic_img = GenericImg::new_from_path_async(path, config).await;
448        Self { generic_img }
449    }
450
451    pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
452        let generic_img = GenericImg::new_from_buf(buf, config);
453        Self { generic_img }
454    }
455
456    pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
457        let generic_img = GenericImg::new_from_reader(reader, config);
458        Self { generic_img }
459    }
460}
461
462/// Component which represents a roughness img. Assumes it is stored as
463/// perceptual roughness/
464pub struct RoughnessImg {
465    pub generic_img: GenericImg,
466}
467impl RoughnessImg {
468    pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
469        let generic_img = GenericImg::new_from_path(path, config);
470        Self { generic_img }
471    }
472
473    pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
474        let generic_img = GenericImg::new_from_path_async(path, config).await;
475        Self { generic_img }
476    }
477
478    pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
479        let generic_img = GenericImg::new_from_buf(buf, config);
480        Self { generic_img }
481    }
482
483    pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
484        let generic_img = GenericImg::new_from_reader(reader, config);
485        Self { generic_img }
486    }
487}
488
489//implement some atributes for the vertex atributes so we can use them in a
490// generic function also implement common things like the atom size of an
491// element which is f32 for most or u32 for faces and edges https://stackoverflow.com/a/53085395
492//https://stackoverflow.com/a/66794115
493// pub trait CpuAtrib<T> {
494//     // type TypeElement;
495//     fn byte_size_element(&self) -> usize;
496//     // pub fn get_data(&self) -> DMatrix<Self::TypeElement>;
497//     fn data_ref(&self) -> &DMatrix<T>;
498// }
499
500// impl CpuAtrib<f32> for Colors {
501//     fn byte_size_element(&self) -> usize {
502//         std::mem::size_of::<f32>()
503//     }
504//     fn data_ref(&self) -> &DMatrix<f32> {
505//         &self.0
506//     }
507// }
508
509/// Environment map based ambient lighting representing light from distant
510/// scenery.
511///
512/// When added as a resource to the scene, this component adds indirect light
513/// to every point of the scene (including inside, enclosed areas) based on
514/// an environment cubemap texture. This is similar to [`crate::AmbientLight`],
515/// but higher quality, and is intended for outdoor scenes.
516///
517/// The environment map must be prefiltered into a diffuse and specular cubemap
518/// based on the [split-sum approximation](https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf).
519///
520/// To prefilter your environment map, you can use `KhronosGroup`'s [glTF-IBL-Sampler](https://github.com/KhronosGroup/glTF-IBL-Sampler).
521/// The diffuse map uses the Lambertian distribution, and the specular map uses
522/// the GGX distribution.
523///
524/// `KhronosGroup` also has several prefiltered environment maps that can be found [here](https://github.com/KhronosGroup/glTF-Sample-Environments)
525pub struct EnvironmentMap {
526    pub diffuse_path: String,
527    pub specular_path: String,
528}
529impl EnvironmentMap {
530    pub fn new_from_path(diffuse_path: &str, specular_path: &str) -> Self {
531        Self {
532            diffuse_path: String::from(diffuse_path),
533            specular_path: String::from(specular_path),
534        }
535    }
536}
537
538// /so we can use the Components inside the Mutex<Hashmap> in the scene and wasm
539// https://stackoverflow.com/a/73773940/22166964
540// shenanigans
541//ConfigDeltas
542#[cfg(target_arch = "wasm32")]
543unsafe impl Send for ConfigChanges {}
544#[cfg(target_arch = "wasm32")]
545unsafe impl Sync for ConfigChanges {}
546//verts
547#[cfg(target_arch = "wasm32")]
548unsafe impl Send for Verts {}
549#[cfg(target_arch = "wasm32")]
550unsafe impl Sync for Verts {}
551//vertse1
552#[cfg(target_arch = "wasm32")]
553unsafe impl Send for EdgesV1 {}
554#[cfg(target_arch = "wasm32")]
555unsafe impl Sync for EdgesV1 {}
556//vertse2
557#[cfg(target_arch = "wasm32")]
558unsafe impl Send for EdgesV2 {}
559#[cfg(target_arch = "wasm32")]
560unsafe impl Sync for EdgesV2 {}
561//edges
562#[cfg(target_arch = "wasm32")]
563unsafe impl Send for Edges {}
564#[cfg(target_arch = "wasm32")]
565unsafe impl Sync for Edges {}
566//faces
567#[cfg(target_arch = "wasm32")]
568unsafe impl Send for Faces {}
569#[cfg(target_arch = "wasm32")]
570unsafe impl Sync for Faces {}
571//uvs
572#[cfg(target_arch = "wasm32")]
573unsafe impl Send for UVs {}
574#[cfg(target_arch = "wasm32")]
575unsafe impl Sync for UVs {}
576//normalss
577#[cfg(target_arch = "wasm32")]
578unsafe impl Send for Normals {}
579#[cfg(target_arch = "wasm32")]
580unsafe impl Sync for Normals {}
581//tangents
582#[cfg(target_arch = "wasm32")]
583unsafe impl Send for Tangents {}
584#[cfg(target_arch = "wasm32")]
585unsafe impl Sync for Tangents {}
586//colors
587#[cfg(target_arch = "wasm32")]
588unsafe impl Send for Colors {}
589#[cfg(target_arch = "wasm32")]
590unsafe impl Sync for Colors {}
591//Diffuseimg
592#[cfg(target_arch = "wasm32")]
593unsafe impl Send for DiffuseImg {}
594#[cfg(target_arch = "wasm32")]
595unsafe impl Sync for DiffuseImg {}
596//Normalimg
597#[cfg(target_arch = "wasm32")]
598unsafe impl Send for NormalImg {}
599#[cfg(target_arch = "wasm32")]
600unsafe impl Sync for NormalImg {}
601//Metalnessimg
602#[cfg(target_arch = "wasm32")]
603unsafe impl Send for MetalnessImg {}
604#[cfg(target_arch = "wasm32")]
605unsafe impl Sync for MetalnessImg {}
606//Roughnessimg
607#[cfg(target_arch = "wasm32")]
608unsafe impl Send for RoughnessImg {}
609#[cfg(target_arch = "wasm32")]
610unsafe impl Sync for RoughnessImg {}
611//EnvironmentMap
612#[cfg(target_arch = "wasm32")]
613unsafe impl Send for EnvironmentMap {}
614#[cfg(target_arch = "wasm32")]
615unsafe impl Sync for EnvironmentMap {}