1extern crate nalgebra as na;
5use gloss_img::DynImage;
9use gloss_utils::{
10 io::FileLoader,
11 tensor::{DynamicTensorFloat2D, DynamicTensorInt2D},
12};
13use image::ImageReader;
14use log::warn;
15use na::DMatrix;
16use std::io::{BufReader, Cursor, Read, Seek};
17#[derive(Clone)]
19pub struct ConfigChanges {
20 pub new_distance_fade_center: na::Point3<f32>,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq)]
25pub enum PointColorType {
26 Solid = 0,
27 PerVert,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq)]
32pub enum LineColorType {
33 Solid = 0,
34 PerVert,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq)]
39pub enum MeshColorType {
40 Solid = 0,
41 PerVert,
42 Texture,
43 UV,
44 Normal,
45 NormalViewCoords,
46}
47
48#[derive(Clone)]
50#[allow(clippy::struct_excessive_bools)]
51pub struct VisLines {
52 pub show_lines: bool,
53 pub line_color: na::Vector4<f32>,
54 pub line_width: f32,
55 pub color_type: LineColorType,
56 pub zbuffer: bool,
57 pub antialias_edges: bool,
58 pub added_automatically: bool,
62}
63#[derive(Clone)]
65pub struct VisWireframe {
66 pub show_wireframe: bool,
67 pub wire_color: na::Vector4<f32>,
68 pub wire_width: f32,
69 pub added_automatically: bool,
73}
74#[derive(Clone)]
76pub struct VisNormals {
77 pub show_normals: bool,
78 pub normals_color: na::Vector4<f32>,
79 pub normals_width: f32,
80 pub normals_scale: f32, pub added_automatically: bool,
85}
86#[derive(Clone)]
88#[allow(clippy::struct_excessive_bools)]
89pub struct VisPoints {
90 pub show_points: bool,
91 pub show_points_indices: bool,
92 pub point_color: na::Vector4<f32>,
93 pub point_size: f32,
94 pub is_point_size_in_world_space: bool,
95 pub color_type: PointColorType,
96 pub zbuffer: bool,
97 pub added_automatically: bool,
101}
102#[derive(Clone)]
104pub struct VisMesh {
105 pub show_mesh: bool,
106 pub solid_color: na::Vector4<f32>,
107 pub metalness: f32,
108 pub perceptual_roughness: f32,
109 pub roughness_black_lvl: f32,
110 pub uv_scale: f32,
111 pub opacity: f32,
112 pub needs_sss: bool,
113 pub color_type: MeshColorType,
114 pub added_automatically: bool,
118}
119#[derive(Clone)]
121pub struct VisOutline {
122 pub show_outline: bool,
123 pub outline_color: na::Vector4<f32>,
124 pub outline_width: f32,
125 pub added_automatically: bool,
129}
130impl Default for VisLines {
132 fn default() -> VisLines {
133 VisLines {
134 show_lines: false,
135 line_color: na::Vector4::<f32>::new(1.0, 0.1, 0.1, 1.0),
136 line_width: 1.0,
137 color_type: LineColorType::Solid,
138 zbuffer: true,
139 antialias_edges: false,
140 added_automatically: false,
141 }
142 }
143}
144impl Default for VisWireframe {
145 fn default() -> VisWireframe {
146 VisWireframe {
147 show_wireframe: false,
148 wire_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
149 wire_width: 1.0,
150 added_automatically: false,
151 }
152 }
153}
154impl Default for VisNormals {
155 fn default() -> VisNormals {
156 VisNormals {
157 show_normals: false,
158 normals_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
159 normals_width: 1.0,
160 normals_scale: 1.0,
161 added_automatically: false,
162 }
163 }
164}
165impl Default for VisPoints {
166 fn default() -> VisPoints {
167 VisPoints {
168 show_points: false,
169 show_points_indices: false,
170 point_color: na::Vector4::<f32>::new(245.0 / 255.0, 175.0 / 255.0, 110.0 / 255.0, 1.0),
171 point_size: 1.0,
172 is_point_size_in_world_space: false,
173 color_type: PointColorType::Solid,
174 zbuffer: true,
175 added_automatically: false,
176 }
177 }
178}
179impl Default for VisMesh {
180 fn default() -> VisMesh {
181 VisMesh {
182 show_mesh: true,
183 solid_color: na::Vector4::<f32>::new(1.0, 206.0 / 255.0, 143.0 / 255.0, 1.0),
184 metalness: 0.0,
185 perceptual_roughness: 0.5,
186 roughness_black_lvl: 0.0,
187 uv_scale: 1.0,
188 opacity: 1.0,
189 needs_sss: false,
190 color_type: MeshColorType::Solid,
191 added_automatically: false,
192 }
193 }
194}
195impl Default for VisOutline {
196 fn default() -> VisOutline {
197 VisOutline {
198 show_outline: false,
199 outline_color: na::Vector4::<f32>::new(0.29, 0.82, 0.73, 1.0), outline_width: 5.0,
201 added_automatically: false,
202 }
203 }
204}
205
206#[derive(Clone)]
209pub struct ModelMatrix(pub na::SimilarityMatrix3<f32>); impl Default for ModelMatrix {
213 fn default() -> ModelMatrix {
214 ModelMatrix(na::SimilarityMatrix3::<f32>::identity())
215 }
216}
217impl ModelMatrix {
218 #[must_use]
219 pub fn with_translation(self, t: &na::Vector3<f32>) -> Self {
220 let mut mat = self;
221 mat.0.append_translation_mut(&na::Translation3::new(t[0], t[1], t[2]));
222 mat
223 }
224 #[must_use]
225 pub fn with_rotation_rot3(self, r: &na::Rotation3<f32>) -> Self {
226 let mut mat = self;
227 mat.0.append_rotation_mut(r);
228 mat
229 }
230 #[must_use]
231 pub fn with_rotation_axis_angle(self, v: &na::Vector3<f32>) -> Self {
232 let mut mat = self;
233 mat.0
234 .append_rotation_mut(&na::Rotation3::from_axis_angle(&na::UnitVector3::<f32>::new_normalize(*v), v.norm()));
235 mat
236 }
237 #[must_use]
238 pub fn with_rotation_euler(self, e: &na::Vector3<f32>) -> Self {
239 let mut mat = self;
240 mat.0.append_rotation_mut(&na::Rotation3::from_euler_angles(e.x, e.y, e.z));
241 mat
242 }
243 #[must_use]
244 pub fn interpolate(&self, other: &Self, other_weight: f32) -> Self {
245 if !(0.0..=1.0).contains(&other_weight) {
246 warn!("pose interpolation weight is outside the [0,1] range, will clamp. Weight is {other_weight}");
247 }
248 let other_weight = other_weight.clamp(0.0, 1.0);
249
250 let lerp_isometry = self.0.isometry.lerp_slerp(&other.0.isometry, other_weight);
251 let lerp_scaling = self.0.scaling() * (1.0 - other_weight) + other.0.scaling() * other_weight;
252
253 let lerp_similarity = na::SimilarityMatrix3::from_parts(lerp_isometry.translation, lerp_isometry.rotation, lerp_scaling);
254
255 ModelMatrix(lerp_similarity)
256 }
257}
258
259#[derive(Clone, Debug)]
261pub struct CamTrack(pub DMatrix<f32>);
262
263#[derive(Clone, Debug)]
264pub struct Verts(pub DynamicTensorFloat2D);
265
266#[derive(Clone, Debug)]
269pub struct EdgesV1(pub DynamicTensorFloat2D);
270#[derive(Clone, Debug)]
273pub struct EdgesV2(pub DynamicTensorFloat2D);
274
275#[derive(Clone)]
280pub struct Faces(pub DynamicTensorInt2D);
281
282#[derive(Clone, Debug)]
285pub struct Edges(pub DynamicTensorInt2D);
286
287#[derive(Clone)]
289pub struct UVs(pub DynamicTensorFloat2D);
290#[derive(Clone)]
296pub struct Normals(pub DynamicTensorFloat2D);
297
298#[derive(Clone)]
300pub struct Tangents(pub DynamicTensorFloat2D);
301
302#[derive(Clone)]
304pub struct Colors(pub DynamicTensorFloat2D);
305
306#[derive(Clone)]
307#[allow(clippy::struct_excessive_bools)]
308pub struct ImgConfig {
309 pub keep_on_cpu: bool,
310 pub fast_upload: bool, pub generate_mipmaps: bool,
312 pub mipmap_generation_cpu: bool,
313}
314impl Default for ImgConfig {
315 fn default() -> Self {
316 Self {
317 keep_on_cpu: true,
318 fast_upload: true,
319 generate_mipmaps: true,
320 mipmap_generation_cpu: false,
321 }
322 }
323}
324
325#[derive(Clone)]
328pub struct GenericImg {
329 pub path: Option<String>,
330 pub cpu_img: Option<DynImage>, pub config: ImgConfig,
332}
333impl GenericImg {
334 pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
337 let cpu_img = Some(ImageReader::open(path).unwrap().decode().unwrap());
338
339 Self {
340 path: Some(path.to_string()),
341 cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
342 config: config.clone(),
343 }
344 }
345
346 pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
349 let reader = ImageReader::new(BufReader::new(FileLoader::open(path).await))
350 .with_guessed_format()
351 .expect("Cursor io never fails");
352
353 let cpu_img = Some(reader.decode().unwrap());
354
355 Self {
356 path: Some(path.to_string()),
357 cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
358 config: config.clone(),
359 }
360 }
361
362 pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
365 Self::new_from_reader(Cursor::new(buf), config)
366 }
367
368 pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
371 let reader_img = ImageReader::new(BufReader::new(reader))
372 .with_guessed_format()
373 .expect("Format for image should be something known and valid");
374
375 let cpu_img = Some(reader_img.decode().unwrap());
376
377 Self {
378 path: None,
379 cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
380 config: config.clone(),
381 }
382 }
383
384 pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
388 use image::{DynamicImage, GrayAlphaImage, GrayImage, RgbImage, RgbaImage};
389
390 let cpu_img = match channels {
391 1 => {
392 let gray_img = GrayImage::from_raw(width, height, pixels).expect("Failed to create grayscale image from raw pixels");
393 Some(DynamicImage::ImageLuma8(gray_img))
394 }
395 2 => {
396 let gray_alpha_img = GrayAlphaImage::from_raw(width, height, pixels).expect("Failed to create grayscale+alpha image from raw pixels");
397 Some(DynamicImage::ImageLumaA8(gray_alpha_img))
398 }
399 3 => {
400 let rgb_img = RgbImage::from_raw(width, height, pixels).expect("Failed to create RGB image from raw pixels");
401 Some(DynamicImage::ImageRgb8(rgb_img))
402 }
403 4 => {
404 let rgba_img = RgbaImage::from_raw(width, height, pixels).expect("Failed to create RGBA image from raw pixels");
405 Some(DynamicImage::ImageRgba8(rgba_img))
406 }
407 _ => panic!("Unsupported number of channels: {channels}. Supported: 1 (Luma), 2 (LumaA), 3 (RGB), 4 (RGBA)"),
408 };
409
410 Self {
411 path: None,
412 cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
413 config: config.clone(),
414 }
415 }
416
417 pub fn img_ref(&self) -> &DynImage {
418 self.cpu_img.as_ref().unwrap()
419 }
420
421 pub fn img_ref_mut(&mut self) -> &mut DynImage {
422 self.cpu_img.as_mut().unwrap()
423 }
424}
425
426#[derive(Clone)]
428pub struct DiffuseImg {
429 pub generic_img: GenericImg,
430}
431
432impl DiffuseImg {
433 pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
434 let generic_img = GenericImg::new_from_path(path, config);
435 Self { generic_img }
436 }
437
438 pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
439 let generic_img = GenericImg::new_from_path_async(path, config).await;
440 Self { generic_img }
441 }
442
443 pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
444 let generic_img = GenericImg::new_from_buf(buf, config);
445 Self { generic_img }
446 }
447
448 pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
449 let generic_img = GenericImg::new_from_reader(reader, config);
450 Self { generic_img }
451 }
452
453 pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
454 let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
455 Self { generic_img }
456 }
457}
458
459#[derive(Clone)]
461pub struct NormalImg {
462 pub generic_img: GenericImg,
463}
464
465impl NormalImg {
466 pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
467 let generic_img = GenericImg::new_from_path(path, config);
468 Self { generic_img }
469 }
470
471 pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
472 let generic_img = GenericImg::new_from_path_async(path, config).await;
473 Self { generic_img }
474 }
475
476 pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
477 let generic_img = GenericImg::new_from_buf(buf, config);
478 Self { generic_img }
479 }
480
481 pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
482 let generic_img = GenericImg::new_from_reader(reader, config);
483 Self { generic_img }
484 }
485
486 pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
487 let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
488 Self { generic_img }
489 }
490}
491
492pub struct MetalnessImg {
494 pub generic_img: GenericImg,
495}
496impl MetalnessImg {
497 pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
498 let generic_img = GenericImg::new_from_path(path, config);
499 Self { generic_img }
500 }
501
502 pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
503 let generic_img = GenericImg::new_from_path_async(path, config).await;
504 Self { generic_img }
505 }
506
507 pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
508 let generic_img = GenericImg::new_from_buf(buf, config);
509 Self { generic_img }
510 }
511
512 pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
513 let generic_img = GenericImg::new_from_reader(reader, config);
514 Self { generic_img }
515 }
516
517 pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
518 let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
519 Self { generic_img }
520 }
521}
522
523#[derive(Clone)]
526pub struct RoughnessImg {
527 pub generic_img: GenericImg,
528}
529impl RoughnessImg {
530 pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
531 let generic_img = GenericImg::new_from_path(path, config);
532 Self { generic_img }
533 }
534
535 pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
536 let generic_img = GenericImg::new_from_path_async(path, config).await;
537 Self { generic_img }
538 }
539
540 pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
541 let generic_img = GenericImg::new_from_buf(buf, config);
542 Self { generic_img }
543 }
544
545 pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
546 let generic_img = GenericImg::new_from_reader(reader, config);
547 Self { generic_img }
548 }
549
550 pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
551 let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
552 Self { generic_img }
553 }
554}
555
556pub trait GenericImageGetter {
557 fn generic_img(&self) -> &GenericImg;
558 fn generic_img_mut(&mut self) -> &mut GenericImg;
559}
560
561impl GenericImageGetter for DiffuseImg {
562 fn generic_img(&self) -> &GenericImg {
563 &self.generic_img
564 }
565 fn generic_img_mut(&mut self) -> &mut GenericImg {
566 &mut self.generic_img
567 }
568}
569
570impl GenericImageGetter for NormalImg {
571 fn generic_img(&self) -> &GenericImg {
572 &self.generic_img
573 }
574 fn generic_img_mut(&mut self) -> &mut GenericImg {
575 &mut self.generic_img
576 }
577}
578
579impl GenericImageGetter for RoughnessImg {
580 fn generic_img(&self) -> &GenericImg {
581 &self.generic_img
582 }
583 fn generic_img_mut(&mut self) -> &mut GenericImg {
584 &mut self.generic_img
585 }
586}
587
588impl GenericImageGetter for MetalnessImg {
589 fn generic_img(&self) -> &GenericImg {
590 &self.generic_img
591 }
592 fn generic_img_mut(&mut self) -> &mut GenericImg {
593 &mut self.generic_img
594 }
595}
596
597pub struct EnvironmentMap {
634 pub diffuse_path: String,
635 pub specular_path: String,
636}
637impl EnvironmentMap {
638 pub fn new_from_path(diffuse_path: &str, specular_path: &str) -> Self {
639 Self {
640 diffuse_path: String::from(diffuse_path),
641 specular_path: String::from(specular_path),
642 }
643 }
644}
645
646#[derive(Clone)]
649pub struct BoundingBox {
650 pub min: na::Point3<f32>,
651 pub max: na::Point3<f32>,
652}
653impl BoundingBox {
654 pub fn new(min: na::Point3<f32>, max: na::Point3<f32>) -> Self {
655 Self { min, max }
656 }
657 pub fn from_center_and_scale(center: &na::Point3<f32>, scale: &na::Vector3<f32>) -> Self {
658 let half_scale = scale / 2.0;
659 Self {
660 min: na::Point3::from(center.coords - half_scale),
661 max: na::Point3::from(center.coords + half_scale),
662 }
663 }
664 pub fn center(&self) -> na::Point3<f32> {
665 na::Point3::from((self.min.coords + self.max.coords) / 2.0)
666 }
667 pub fn size(&self) -> na::Vector3<f32> {
668 self.max.coords - self.min.coords
669 }
670 pub fn diagonal_length(&self) -> f32 {
671 (self.max.coords - self.min.coords).norm()
672 }
673}
674
675#[cfg(target_arch = "wasm32")]
680unsafe impl Send for ConfigChanges {}
681#[cfg(target_arch = "wasm32")]
682unsafe impl Sync for ConfigChanges {}
683#[cfg(target_arch = "wasm32")]
685unsafe impl Send for Verts {}
686#[cfg(target_arch = "wasm32")]
687unsafe impl Sync for Verts {}
688#[cfg(target_arch = "wasm32")]
690unsafe impl Send for EdgesV1 {}
691#[cfg(target_arch = "wasm32")]
692unsafe impl Sync for EdgesV1 {}
693#[cfg(target_arch = "wasm32")]
695unsafe impl Send for EdgesV2 {}
696#[cfg(target_arch = "wasm32")]
697unsafe impl Sync for EdgesV2 {}
698#[cfg(target_arch = "wasm32")]
700unsafe impl Send for Edges {}
701#[cfg(target_arch = "wasm32")]
702unsafe impl Sync for Edges {}
703#[cfg(target_arch = "wasm32")]
705unsafe impl Send for Faces {}
706#[cfg(target_arch = "wasm32")]
707unsafe impl Sync for Faces {}
708#[cfg(target_arch = "wasm32")]
710unsafe impl Send for UVs {}
711#[cfg(target_arch = "wasm32")]
712unsafe impl Sync for UVs {}
713#[cfg(target_arch = "wasm32")]
715unsafe impl Send for Normals {}
716#[cfg(target_arch = "wasm32")]
717unsafe impl Sync for Normals {}
718#[cfg(target_arch = "wasm32")]
720unsafe impl Send for Tangents {}
721#[cfg(target_arch = "wasm32")]
722unsafe impl Sync for Tangents {}
723#[cfg(target_arch = "wasm32")]
725unsafe impl Send for Colors {}
726#[cfg(target_arch = "wasm32")]
727unsafe impl Sync for Colors {}
728#[cfg(target_arch = "wasm32")]
730unsafe impl Send for DiffuseImg {}
731#[cfg(target_arch = "wasm32")]
732unsafe impl Sync for DiffuseImg {}
733#[cfg(target_arch = "wasm32")]
735unsafe impl Send for NormalImg {}
736#[cfg(target_arch = "wasm32")]
737unsafe impl Sync for NormalImg {}
738#[cfg(target_arch = "wasm32")]
740unsafe impl Send for MetalnessImg {}
741#[cfg(target_arch = "wasm32")]
742unsafe impl Sync for MetalnessImg {}
743#[cfg(target_arch = "wasm32")]
745unsafe impl Send for RoughnessImg {}
746#[cfg(target_arch = "wasm32")]
747unsafe impl Sync for RoughnessImg {}
748#[cfg(target_arch = "wasm32")]
750unsafe impl Send for EnvironmentMap {}
751#[cfg(target_arch = "wasm32")]
752unsafe impl Sync for EnvironmentMap {}