From 9b6f823670516043cb999b907a5e72f8fd3fd849 Mon Sep 17 00:00:00 2001 From: Asger Nyman Christiansen Date: Wed, 13 Nov 2024 10:16:52 +0100 Subject: [PATCH 1/5] Update dependencies --- Cargo.toml | 8 ++++---- src/io/pcd.rs | 2 +- src/lib.rs | 2 +- test_data/test.png | Bin 80 -> 86 bytes test_data/test.tga | Bin 34 -> 36 bytes 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27cb015..d9891ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,14 +46,14 @@ serde = ["dep:serde", "half/serde", "cgmath/serde"] [dependencies] cgmath = "0.18" half = {version="2", features=["std", "num-traits", "zerocopy"]} -thiserror = "1" -reqwest = {version = "0.11", optional = true, default-features = false } +thiserror = "2" +reqwest = {version = "0.12", optional = true, default-features = false } gltf = { version = "1", optional = true, features=["KHR_materials_ior", "KHR_materials_transmission"] } wavefront_obj = { version = "10", optional = true } stl_io = { version = "0.8.2", optional = true } image = { version = "0.24", optional = true, default-features = false} -resvg = { version = "0.43.0", optional = true } -pcd-rs = { version = "0.10", optional = true, features = ["derive"] } +resvg = { version = "0.44.0", optional = true } +pcd-rs = { version = "0.12", optional = true, features = ["derive"] } data-url = {version = "0.3", optional = true } serde = {version= "1", optional = true, features = ["derive", "rc"] } diff --git a/src/io/pcd.rs b/src/io/pcd.rs index ace1e1f..59696a7 100644 --- a/src/io/pcd.rs +++ b/src/io/pcd.rs @@ -13,7 +13,7 @@ pub fn deserialize_pcd(raw_assets: &mut RawAssets, path: &PathBuf) -> Result>>()?; + let points = reader.collect::>>()?; let positions = points .iter() .map(|p| { diff --git a/src/lib.rs b/src/lib.rs index 7df2c3e..34aef5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,7 +229,7 @@ pub enum Error { #[cfg(feature = "pcd")] #[error("error while parsing an .pcd file")] - Pcd(#[from] pcd_rs::anyhow::Error), + Pcd(#[from] pcd_rs::Error), #[cfg(any(not(target_arch = "wasm32"), feature = "stl"))] #[error("io error")] diff --git a/test_data/test.png b/test_data/test.png index 2eed7d082ef0b27ec9e34b12e4c29831b6811835..9667fccfce191725e0d3e79c20ffc65e0a5ea672 100644 GIT binary patch delta 55 zcmWFto1kJO>*?YcQo+b5#PIe%0}%WNl3)ZP{u|$8`{lxQ>=j7H)78&qol`;+0RFiX AJ^%m! delta 49 zcmWFwn4qE~?&;zfQo)#gTe~DWM4f Dc%}}T diff --git a/test_data/test.tga b/test_data/test.tga index b3a8be4110d5dfcc734bf1c2c376118c058ae2a8..6d01fda6682ea282ac3f550407f335ff58d40a43 100644 GIT binary patch literal 36 fcmZQz;9`IQCI%)31&szE_dgR5|7QTg|3C%+LNo`` literal 34 ccmZQzU}As)CLmiu1IYUiME`*#kYM-^05)w0NB{r; From f9dcec4426bbfc3dbbb472d6aabeb09c545aaeaf Mon Sep 17 00:00:00 2001 From: Asger Nyman Christiansen Date: Wed, 13 Nov 2024 10:48:04 +0100 Subject: [PATCH 2/5] Update image dependency --- Cargo.toml | 2 +- src/io/img.rs | 82 +++++++++++++++++++++++--------------------- test_data/test.jpeg | Bin 862 -> 691 bytes test_data/test.jpg | Bin 862 -> 691 bytes 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d9891ff..ee8270a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ reqwest = {version = "0.12", optional = true, default-features = false } gltf = { version = "1", optional = true, features=["KHR_materials_ior", "KHR_materials_transmission"] } wavefront_obj = { version = "10", optional = true } stl_io = { version = "0.8.2", optional = true } -image = { version = "0.24", optional = true, default-features = false} +image = { version = "0.25", optional = true, default-features = false} resvg = { version = "0.44.0", optional = true } pcd-rs = { version = "0.12", optional = true, features = ["derive"] } data-url = {version = "0.3", optional = true } diff --git a/src/io/img.rs b/src/io/img.rs index a925c42..0338835 100644 --- a/src/io/img.rs +++ b/src/io/img.rs @@ -1,5 +1,5 @@ use crate::{io::RawAssets, texture::*, Error, Result}; -use image::{io::Reader, *}; +use image::*; use std::io::Cursor; use std::path::Path; @@ -10,34 +10,13 @@ pub fn deserialize_img(path: impl AsRef, bytes: &[u8]) -> Result>(), - ), - width: metadata.width, - height: metadata.height, - ..Default::default() - }); - } let img: DynamicImage = reader.decode()?; let width = img.width(); let height = img.height(); @@ -61,6 +40,12 @@ pub fn deserialize_img(path: impl AsRef, bytes: &[u8]) -> Result>(), ), + DynamicImage::ImageRgb32F(img) => TextureData::RgbF32( + img.into_raw() + .chunks(3) + .map(|c| [c[0], c[1], c[2]]) + .collect::>(), + ), _ => unimplemented!(), }; Ok(Texture2D { @@ -114,42 +99,42 @@ pub fn deserialize_svg(path: impl AsRef, bytes: &[u8]) -> Result Result { #![allow(unreachable_code)] #![allow(unused_variables)] - let format: image::ImageOutputFormat = match path.extension().unwrap().to_str().unwrap() { + let format: ImageFormat = match path.extension().unwrap().to_str().unwrap() { "png" => { #[cfg(not(feature = "png"))] return Err(Error::FeatureMissing("png".to_string())); #[cfg(feature = "png")] - image::ImageOutputFormat::Png + ImageFormat::Png } "jpeg" | "jpg" => { #[cfg(not(feature = "jpeg"))] return Err(Error::FeatureMissing("jpeg".to_string())); #[cfg(feature = "jpeg")] - image::ImageOutputFormat::Jpeg(100) + ImageFormat::Jpeg } "bmp" => { #[cfg(not(feature = "bmp"))] return Err(Error::FeatureMissing("bmp".to_string())); #[cfg(feature = "bmp")] - image::ImageOutputFormat::Bmp + ImageFormat::Bmp } "tga" => { #[cfg(not(feature = "tga"))] return Err(Error::FeatureMissing("tga".to_string())); #[cfg(feature = "tga")] - image::ImageOutputFormat::Tga + ImageFormat::Tga } "tiff" | "tif" => { #[cfg(not(feature = "tiff"))] return Err(Error::FeatureMissing("tiff".to_string())); #[cfg(feature = "tiff")] - image::ImageOutputFormat::Tiff + ImageFormat::Tiff } "gif" => { #[cfg(not(feature = "gif"))] return Err(Error::FeatureMissing("gif".to_string())); #[cfg(feature = "gif")] - image::ImageOutputFormat::Gif + ImageFormat::Gif } _ => return Err(Error::FailedSerialize(path.to_str().unwrap().to_string())), }; @@ -173,14 +158,29 @@ pub fn serialize_img(tex: &Texture2D, path: &Path) -> Result { ) .unwrap(), ), - TextureData::RgbaU8(data) => DynamicImage::ImageRgba8( - ImageBuffer::from_raw( - tex.width, - tex.height, - data.iter().flat_map(|v| *v).collect::>(), - ) - .unwrap(), - ), + TextureData::RgbaU8(data) => { + if format == ImageFormat::Jpeg { + DynamicImage::ImageRgb8( + ImageBuffer::from_raw( + tex.width, + tex.height, + data.iter() + .flat_map(|v| [v[0], v[1], v[2]]) + .collect::>(), + ) + .unwrap(), + ) + } else { + DynamicImage::ImageRgba8( + ImageBuffer::from_raw( + tex.width, + tex.height, + data.iter().flat_map(|v| *v).collect::>(), + ) + .unwrap(), + ) + } + } _ => unimplemented!(), }; let mut bytes: Vec = Vec::new(); @@ -212,7 +212,11 @@ mod test { if format == "jpeg" || format == "jpg" { if let crate::TextureData::RgbU8(data) = tex.data { - assert_eq!(data, vec![[4, 0, 0], [250, 0, 1], [0, 254, 1], [1, 2, 253]]); + // Jpeg is not lossless + assert_eq!( + data, + vec![[47, 0, 18], [227, 0, 0], [0, 245, 0], [15, 32, 255]] + ); } else { panic!("Wrong texture data: {:?}", tex.data) } diff --git a/test_data/test.jpeg b/test_data/test.jpeg index a255563f3ef5a79d72f7a6069772a9fffa13fc2f..7c9e4f5ed7d54ea1f58355d598f55550ce83be3b 100644 GIT binary patch delta 214 zcmcb|wwZN;PCW-38#@~-2Rl1ECnpCNj|eXhH#d)@kTAc9tdzW*tdxw5f{LEHf|8E1 zjEsi4rjCK3iHV84x}~j!k&T|QiP8Vt49<+4oSZz|JQBRT5=M$Libf;=Hi+7d8}~7~ ze0m!dsrz;Ii^PeGyR16}1^Gln3>g@#7~_|wRE9Ba3vXK))S{{x+?;z%ciW?Nx3{hR Ynl8s~c1BEWR_OB&>$mEiKJ))305vx`X8-^I delta 386 zcmdnYdXH^_PCX-q;Qws~X9|p9gXrD3aUWy-zu5g5zV)#m+K->_lN0_hZ|mxc_(S)^ zf9(ILe|VqNhwJU7(r3jF|C9UhuluoWw(rF)w)}3F)3#mSGFRU7^4hg;OwJk|x_9r? zp;Pyyqa%`Ll*Wz}sU1z? z_Lw}<(|lBLPVTd?=o zBkiQ@kd^vJY#4tf*XnK9$5Nr$cDPo{ZsLs^JNZNYd>R3VFMK?Fg@#7~_|wRE9Ba3vXK))S{{x+?;z%ciW?Nx3{hR Ynl8s~c1BEWR_OB&>$mEiKJ))305vx`X8-^I delta 386 zcmdnYdXH^_PCX-q;Qws~X9|p9gXrD3aUWy-zu5g5zV)#m+K->_lN0_hZ|mxc_(S)^ zf9(ILe|VqNhwJU7(r3jF|C9UhuluoWw(rF)w)}3F)3#mSGFRU7^4hg;OwJk|x_9r? zp;Pyyqa%`Ll*Wz}sU1z? z_Lw}<(|lBLPVTd?=o zBkiQ@kd^vJY#4tf*XnK9$5Nr$cDPo{ZsLs^JNZNYd>R3VFMK?F Date: Wed, 13 Nov 2024 11:20:10 +0100 Subject: [PATCH 3/5] Camera::up_orthogonal --- src/camera.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/camera.rs b/src/camera.rs index 94908fa..4fdbfb5 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -511,12 +511,20 @@ impl Camera { } /// - /// Returns the up direction of this camera (might not be orthogonal to the view direction). + /// Returns the up direction of this camera. + /// This will probably not be orthogonal to the view direction, use [up_orthogonal](Camera::up_orthogonal) instead if that is needed. /// pub fn up(&self) -> &Vec3 { &self.up } + /// + /// Returns the up direction of this camera that is orthogonal to the view direction. + /// + pub fn up_orthogonal(&self) -> Vec3 { + self.right_direction().cross(self.view_direction()) + } + /// /// Returns the view direction of this camera, ie. the direction the camera is looking. /// From 7473c05a9464a0d7ec07a993c1bc494214c7e419 Mon Sep 17 00:00:00 2001 From: Asger Nyman Christiansen Date: Wed, 13 Nov 2024 11:25:49 +0100 Subject: [PATCH 4/5] Fix #39 --- src/camera.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/camera.rs b/src/camera.rs index 4fdbfb5..647ced1 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -560,7 +560,9 @@ impl Camera { if let ProjectionType::Perspective { .. } = self.projection_type { v[3] = vec4(0.0, 0.0, 0.0, 1.0); } - self.screen2ray = (self.projection * v).invert().unwrap(); + self.screen2ray = (self.projection * v) + .invert() + .unwrap_or_else(|| Mat4::identity()); } fn update_frustrum(&mut self) { From 2aa308fe43a23f57b5736e4e1535279882d5ece5 Mon Sep 17 00:00:00 2001 From: Alan Everett Date: Wed, 13 Nov 2024 07:36:15 -0500 Subject: [PATCH 5/5] Scale camera zoom based on distance to target (#40) * Scale camera zoom based on distance to target * Fix screen2ray scaling with zoom * Fix zoom_towards when point is not target * Add zoom function * Safety check --------- Co-authored-by: Asger Nyman Christiansen --- src/camera.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 647ced1..34ce012 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -298,6 +298,7 @@ impl Camera { Point3::from_vec(self.target), self.up, ); + self.view[3][3] *= position.distance(target); self.update_screen2ray(); self.update_frustrum(); } @@ -557,6 +558,7 @@ impl Camera { fn update_screen2ray(&mut self) { let mut v = self.view; + v /= v[3][3]; if let ProjectionType::Perspective { .. } = self.projection_type { v[3] = vec4(0.0, 0.0, 0.0, 1.0); } @@ -676,8 +678,17 @@ impl Camera { } } + /// + /// Moves the camera towards the camera target by the amount delta while keeping the given minimum and maximum distance to the target. + /// + pub fn zoom(&mut self, delta: f32, minimum_distance: f32, maximum_distance: f32) { + let target = self.target; + self.zoom_towards(&target, delta, minimum_distance, maximum_distance); + } + /// /// Moves the camera towards the given point by the amount delta while keeping the given minimum and maximum distance to the point. + /// Note that the camera target is also updated so that the view direction is the same. /// pub fn zoom_towards( &mut self, @@ -694,17 +705,15 @@ impl Camera { let position = *self.position(); let distance = point.distance(position); - let direction = (point - position).normalize(); - let target = *self.target(); - let up = self.up; - let new_distance = (distance - delta).clamp(minimum_distance, maximum_distance); - let new_position = point - direction * new_distance; - self.set_view(new_position, new_position + (target - position), up); - if let ProjectionType::Orthographic { height } = self.projection_type() { - let h = new_distance * height / distance; - let z_near = self.z_near(); - let z_far = self.z_far(); - self.set_orthographic_projection(h, z_near, z_far); + if distance > f32::EPSILON { + let delta_clamped = + distance - (distance - delta).clamp(minimum_distance, maximum_distance); + let v = (point - position) * delta_clamped / distance; + self.set_view( + self.position + v, + self.target + v - v.project_on(self.view_direction()), + self.up, + ); } } }