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