extern crate nalgebra as na;
use gloss_img::DynImage;
use gloss_utils::io::FileLoader;
use image::ImageReader;
use log::warn;
use na::DMatrix;
use num_derive::FromPrimitive;
use std::io::{BufReader, Cursor, Read, Seek};
#[derive(Clone)]
pub struct ConfigChanges {
pub new_distance_fade_center: na::Point3<f32>,
}
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
pub enum PointColorType {
Solid = 0,
PerVert,
}
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
pub enum LineColorType {
Solid = 0,
PerVert,
}
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
pub enum MeshColorType {
Solid = 0,
PerVert,
Texture,
UV,
Normal,
NormalViewCoords,
}
#[derive(Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct VisLines {
pub show_lines: bool,
pub line_color: na::Vector4<f32>,
pub line_width: f32,
pub color_type: LineColorType,
pub zbuffer: bool,
pub antialias_edges: bool,
pub added_automatically: bool,
}
#[derive(Clone)]
pub struct VisWireframe {
pub show_wireframe: bool,
pub wire_color: na::Vector4<f32>,
pub wire_width: f32,
pub added_automatically: bool,
}
#[derive(Clone)]
pub struct VisNormals {
pub show_normals: bool,
pub normals_color: na::Vector4<f32>,
pub normals_width: f32,
pub normals_scale: f32, pub added_automatically: bool,
}
#[derive(Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct VisPoints {
pub show_points: bool,
pub show_points_indices: bool,
pub point_color: na::Vector4<f32>,
pub point_size: f32,
pub is_point_size_in_world_space: bool,
pub color_type: PointColorType,
pub zbuffer: bool,
pub added_automatically: bool,
}
#[derive(Clone)]
pub struct VisMesh {
pub show_mesh: bool,
pub solid_color: na::Vector4<f32>,
pub metalness: f32,
pub perceptual_roughness: f32,
pub roughness_black_lvl: f32,
pub uv_scale: f32,
pub opacity: f32,
pub needs_sss: bool,
pub color_type: MeshColorType,
pub added_automatically: bool,
}
#[derive(Clone)]
pub struct VisOutline {
pub show_outline: bool,
pub outline_color: na::Vector4<f32>,
pub outline_width: f32,
pub added_automatically: bool,
}
impl Default for VisLines {
fn default() -> VisLines {
VisLines {
show_lines: false,
line_color: na::Vector4::<f32>::new(1.0, 0.1, 0.1, 1.0),
line_width: 1.0,
color_type: LineColorType::Solid,
zbuffer: true,
antialias_edges: false,
added_automatically: false,
}
}
}
impl Default for VisWireframe {
fn default() -> VisWireframe {
VisWireframe {
show_wireframe: false,
wire_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
wire_width: 1.0,
added_automatically: false,
}
}
}
impl Default for VisNormals {
fn default() -> VisNormals {
VisNormals {
show_normals: false,
normals_color: na::Vector4::<f32>::new(1.0, 0.0, 0.0, 1.0),
normals_width: 1.0,
normals_scale: 1.0,
added_automatically: false,
}
}
}
impl Default for VisPoints {
fn default() -> VisPoints {
VisPoints {
show_points: false,
show_points_indices: false,
point_color: na::Vector4::<f32>::new(245.0 / 255.0, 175.0 / 255.0, 110.0 / 255.0, 1.0),
point_size: 1.0,
is_point_size_in_world_space: false,
color_type: PointColorType::Solid,
zbuffer: true,
added_automatically: false,
}
}
}
impl Default for VisMesh {
fn default() -> VisMesh {
VisMesh {
show_mesh: true,
solid_color: na::Vector4::<f32>::new(1.0, 206.0 / 255.0, 143.0 / 255.0, 1.0),
metalness: 0.0,
perceptual_roughness: 0.5,
roughness_black_lvl: 0.0,
uv_scale: 1.0,
opacity: 1.0,
needs_sss: false,
color_type: MeshColorType::Solid,
added_automatically: false,
}
}
}
impl Default for VisOutline {
fn default() -> VisOutline {
VisOutline {
show_outline: false,
outline_color: na::Vector4::<f32>::new(0.29, 0.82, 0.73, 1.0), outline_width: 5.0,
added_automatically: false,
}
}
}
#[derive(Clone)]
pub struct ModelMatrix(pub na::SimilarityMatrix3<f32>); impl Default for ModelMatrix {
fn default() -> ModelMatrix {
ModelMatrix(na::SimilarityMatrix3::<f32>::identity())
}
}
impl ModelMatrix {
#[must_use]
pub fn with_translation(self, t: &na::Vector3<f32>) -> Self {
let mut mat = self;
mat.0.append_translation_mut(&na::Translation3::new(t[0], t[1], t[2]));
mat
}
#[must_use]
pub fn with_rotation_rot3(self, r: &na::Rotation3<f32>) -> Self {
let mut mat = self;
mat.0.append_rotation_mut(r);
mat
}
#[must_use]
pub fn with_rotation_axis_angle(self, v: &na::Vector3<f32>) -> Self {
let mut mat = self;
mat.0
.append_rotation_mut(&na::Rotation3::from_axis_angle(&na::UnitVector3::<f32>::new_normalize(*v), v.norm()));
mat
}
#[must_use]
pub fn with_rotation_euler(self, e: &na::Vector3<f32>) -> Self {
let mut mat = self;
mat.0.append_rotation_mut(&na::Rotation3::from_euler_angles(e.x, e.y, e.z));
mat
}
#[must_use]
pub fn with_scale(self, s: f32) -> Self {
let mut mat = self;
mat.0.append_scaling_mut(s);
mat
}
#[must_use]
pub fn interpolate(&self, other: &Self, other_weight: f32) -> Self {
if !(0.0..=1.0).contains(&other_weight) {
warn!("pose interpolation weight is outside the [0,1] range, will clamp. Weight is {other_weight}");
}
let other_weight = other_weight.clamp(0.0, 1.0);
let lerp_isometry = self.0.isometry.lerp_slerp(&other.0.isometry, other_weight);
let lerp_scaling = self.0.scaling() * (1.0 - other_weight) + other.0.scaling() * other_weight;
let lerp_similarity = na::SimilarityMatrix3::from_parts(lerp_isometry.translation, lerp_isometry.rotation, lerp_scaling);
ModelMatrix(lerp_similarity)
}
}
#[derive(Clone, Debug)]
pub struct CamTrack(pub DMatrix<f32>);
#[derive(Clone, Debug)]
pub struct Verts(pub DMatrix<f32>);
#[derive(Clone, Debug)]
pub struct EdgesV1(pub DMatrix<f32>);
#[derive(Clone, Debug)]
pub struct EdgesV2(pub DMatrix<f32>);
#[derive(Clone)]
pub struct Faces(pub DMatrix<u32>);
#[derive(Clone, Debug)]
pub struct Edges(pub DMatrix<u32>);
#[derive(Clone)]
pub struct UVs(pub DMatrix<f32>);
#[derive(Clone)]
pub struct Normals(pub DMatrix<f32>);
#[derive(Clone)]
pub struct Tangents(pub DMatrix<f32>);
#[derive(Clone)]
pub struct Colors(pub DMatrix<f32>);
#[derive(Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct ImgConfig {
pub keep_on_cpu: bool,
pub fast_upload: bool, pub generate_mipmaps: bool,
pub mipmap_generation_cpu: bool,
}
impl Default for ImgConfig {
fn default() -> Self {
Self {
keep_on_cpu: true,
fast_upload: true,
generate_mipmaps: true,
mipmap_generation_cpu: false,
}
}
}
#[derive(Clone)]
pub struct GenericImg {
pub path: Option<String>,
pub cpu_img: Option<DynImage>, pub config: ImgConfig,
}
impl GenericImg {
pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
let cpu_img = Some(ImageReader::open(path).unwrap().decode().unwrap());
Self {
path: Some(path.to_string()),
cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
config: config.clone(),
}
}
pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
let reader = ImageReader::new(BufReader::new(FileLoader::open(path).await))
.with_guessed_format()
.expect("Cursor io never fails");
let cpu_img = Some(reader.decode().unwrap());
Self {
path: Some(path.to_string()),
cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
config: config.clone(),
}
}
pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
Self::new_from_reader(Cursor::new(buf), config)
}
pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
let reader_img = ImageReader::new(BufReader::new(reader))
.with_guessed_format()
.expect("Format for image should be something known and valid");
let cpu_img = Some(reader_img.decode().unwrap());
Self {
path: None,
cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
config: config.clone(),
}
}
pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
use image::{DynamicImage, GrayAlphaImage, GrayImage, RgbImage, RgbaImage};
let cpu_img = match channels {
1 => {
let gray_img = GrayImage::from_raw(width, height, pixels).expect("Failed to create grayscale image from raw pixels");
Some(DynamicImage::ImageLuma8(gray_img))
}
2 => {
let gray_alpha_img = GrayAlphaImage::from_raw(width, height, pixels).expect("Failed to create grayscale+alpha image from raw pixels");
Some(DynamicImage::ImageLumaA8(gray_alpha_img))
}
3 => {
let rgb_img = RgbImage::from_raw(width, height, pixels).expect("Failed to create RGB image from raw pixels");
Some(DynamicImage::ImageRgb8(rgb_img))
}
4 => {
let rgba_img = RgbaImage::from_raw(width, height, pixels).expect("Failed to create RGBA image from raw pixels");
Some(DynamicImage::ImageRgba8(rgba_img))
}
_ => panic!("Unsupported number of channels: {channels}. Supported: 1 (Luma), 2 (LumaA), 3 (RGB), 4 (RGBA)"),
};
Self {
path: None,
cpu_img: cpu_img.map(|v| v.try_into().unwrap()),
config: config.clone(),
}
}
pub fn img_ref(&self) -> &DynImage {
self.cpu_img.as_ref().unwrap()
}
pub fn img_ref_mut(&mut self) -> &mut DynImage {
self.cpu_img.as_mut().unwrap()
}
}
#[derive(Clone)]
pub struct DiffuseImg {
pub generic_img: GenericImg,
}
impl DiffuseImg {
pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path(path, config);
Self { generic_img }
}
pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path_async(path, config).await;
Self { generic_img }
}
pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_buf(buf, config);
Self { generic_img }
}
pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_reader(reader, config);
Self { generic_img }
}
pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
Self { generic_img }
}
}
#[derive(Clone)]
pub struct NormalImg {
pub generic_img: GenericImg,
}
impl NormalImg {
pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path(path, config);
Self { generic_img }
}
pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path_async(path, config).await;
Self { generic_img }
}
pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_buf(buf, config);
Self { generic_img }
}
pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_reader(reader, config);
Self { generic_img }
}
pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
Self { generic_img }
}
}
pub struct MetalnessImg {
pub generic_img: GenericImg,
}
impl MetalnessImg {
pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path(path, config);
Self { generic_img }
}
pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path_async(path, config).await;
Self { generic_img }
}
pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_buf(buf, config);
Self { generic_img }
}
pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_reader(reader, config);
Self { generic_img }
}
pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
Self { generic_img }
}
}
#[derive(Clone)]
pub struct RoughnessImg {
pub generic_img: GenericImg,
}
impl RoughnessImg {
pub fn new_from_path(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path(path, config);
Self { generic_img }
}
pub async fn new_from_path_async(path: &str, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_path_async(path, config).await;
Self { generic_img }
}
pub fn new_from_buf(buf: &[u8], config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_buf(buf, config);
Self { generic_img }
}
pub fn new_from_reader<R: Read + Seek>(reader: R, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_reader(reader, config);
Self { generic_img }
}
pub fn new_from_raw_pixels(pixels: Vec<u8>, width: u32, height: u32, channels: u8, config: &ImgConfig) -> Self {
let generic_img = GenericImg::new_from_raw_pixels(pixels, width, height, channels, config);
Self { generic_img }
}
}
pub trait GenericImageGetter {
fn generic_img(&self) -> &GenericImg;
fn generic_img_mut(&mut self) -> &mut GenericImg;
}
impl GenericImageGetter for DiffuseImg {
fn generic_img(&self) -> &GenericImg {
&self.generic_img
}
fn generic_img_mut(&mut self) -> &mut GenericImg {
&mut self.generic_img
}
}
impl GenericImageGetter for NormalImg {
fn generic_img(&self) -> &GenericImg {
&self.generic_img
}
fn generic_img_mut(&mut self) -> &mut GenericImg {
&mut self.generic_img
}
}
impl GenericImageGetter for RoughnessImg {
fn generic_img(&self) -> &GenericImg {
&self.generic_img
}
fn generic_img_mut(&mut self) -> &mut GenericImg {
&mut self.generic_img
}
}
impl GenericImageGetter for MetalnessImg {
fn generic_img(&self) -> &GenericImg {
&self.generic_img
}
fn generic_img_mut(&mut self) -> &mut GenericImg {
&mut self.generic_img
}
}
pub trait CpuAtrib<T> {
fn byte_size_element(&self) -> usize;
fn data_ref(&self) -> &DMatrix<T>;
}
impl CpuAtrib<f32> for Verts {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<f32> for EdgesV1 {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<f32> for EdgesV2 {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<u32> for Edges {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<u32>()
}
fn data_ref(&self) -> &DMatrix<u32> {
&self.0
}
}
impl CpuAtrib<u32> for Faces {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<u32>()
}
fn data_ref(&self) -> &DMatrix<u32> {
&self.0
}
}
impl CpuAtrib<f32> for UVs {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<f32> for Normals {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<f32> for Tangents {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
impl CpuAtrib<f32> for Colors {
fn byte_size_element(&self) -> usize {
std::mem::size_of::<f32>()
}
fn data_ref(&self) -> &DMatrix<f32> {
&self.0
}
}
pub struct EnvironmentMap {
pub diffuse_path: String,
pub specular_path: String,
}
impl EnvironmentMap {
pub fn new_from_path(diffuse_path: &str, specular_path: &str) -> Self {
Self {
diffuse_path: String::from(diffuse_path),
specular_path: String::from(specular_path),
}
}
}
#[derive(Clone)]
pub struct BoundingBox {
pub min: na::Point3<f32>,
pub max: na::Point3<f32>,
}
impl BoundingBox {
pub fn new(min: na::Point3<f32>, max: na::Point3<f32>) -> Self {
Self { min, max }
}
pub fn from_center_and_scale(center: &na::Point3<f32>, scale: &na::Vector3<f32>) -> Self {
let half_scale = scale / 2.0;
Self {
min: na::Point3::from(center.coords - half_scale),
max: na::Point3::from(center.coords + half_scale),
}
}
pub fn center(&self) -> na::Point3<f32> {
na::Point3::from((self.min.coords + self.max.coords) / 2.0)
}
pub fn size(&self) -> na::Vector3<f32> {
self.max.coords - self.min.coords
}
pub fn diagonal_length(&self) -> f32 {
(self.max.coords - self.min.coords).norm()
}
}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for ConfigChanges {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for ConfigChanges {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Verts {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Verts {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for EdgesV1 {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for EdgesV1 {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for EdgesV2 {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for EdgesV2 {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Edges {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Edges {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Faces {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Faces {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for UVs {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for UVs {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Normals {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Normals {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Tangents {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Tangents {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for Colors {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for Colors {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for DiffuseImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for DiffuseImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for NormalImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for NormalImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for MetalnessImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for MetalnessImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for RoughnessImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for RoughnessImg {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for EnvironmentMap {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for EnvironmentMap {}