From bc2cfd359cbfaa25f92ab9496339209199aad949 Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Wed, 11 May 2022 17:24:37 +0200 Subject: [PATCH] read pixel --- src/core/al-core/src/texture/pixel.rs | 13 ++++++-- src/core/al-core/src/texture/texture.rs | 41 +++++++++++++------------ src/core/src/app.rs | 10 +++--- src/core/src/healpix/utils.rs | 4 +++ src/core/src/survey/buffer.rs | 39 +++++++++++------------ src/core/src/survey/mod.rs | 20 +++++++----- src/js/HpxImageSurvey.js | 5 +++ 7 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/core/al-core/src/texture/pixel.rs b/src/core/al-core/src/texture/pixel.rs index d9d6340a..206486b3 100644 --- a/src/core/al-core/src/texture/pixel.rs +++ b/src/core/al-core/src/texture/pixel.rs @@ -4,7 +4,7 @@ use wasm_bindgen::JsValue; use crate::webgl_ctx::WebGlContext; pub trait Pixel: - AsRef<[Self::Item]> + Default + std::cmp::PartialEq + std::fmt::Debug + std::clone::Clone + AsRef<[Self::Item]> + Default + std::cmp::PartialEq + std::fmt::Debug + std::clone::Clone + serde::ser::Serialize { type Item: std::cmp::PartialOrd + Clone + Copy + std::fmt::Debug + cgmath::Zero; type Container: ArrayBuffer; @@ -213,6 +213,15 @@ impl Pixel for [i32; 1] { } } +/*impl From for JsValue +where + T: Pixel +{ + fn from(p: T) -> Self { + JsValue::from_serde(&p).unwrap() + } +}*/ +/* pub enum PixelType { RU8([u8; 1]), RI16([i16; 1]), @@ -233,4 +242,4 @@ impl From for JsValue { PixelType::RGBAU8(v) => JsValue::from_serde(&v).unwrap(), } } -} +}*/ diff --git a/src/core/al-core/src/texture/texture.rs b/src/core/al-core/src/texture/texture.rs index be219c1c..0ac861fd 100644 --- a/src/core/al-core/src/texture/texture.rs +++ b/src/core/al-core/src/texture/texture.rs @@ -26,7 +26,7 @@ pub struct Texture2D { } use crate::image::format::ImageFormat; use super::pixel::Pixel; -use super::pixel::PixelType; +//use super::pixel::PixelType; use std::path::Path; impl Texture2D { pub fn create_from_path, F: ImageFormat>( @@ -267,7 +267,7 @@ impl Texture2D { Texture2DBoundMut { texture_2d: self } } - pub fn read_pixel(&self, x: i32, y: i32) -> Result { + pub fn read_pixel(&self, x: i32, y: i32) -> Result { // Create and bind the framebuffer let reader = self.gl.create_framebuffer(); self.gl @@ -306,28 +306,28 @@ impl Texture2D { #[cfg(feature = "webgl2")] let value = match (*format, *type_) { (WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => { - let val = <[u8; 1]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RU8(val)) + let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::SHORT) => { - let val = <[i16; 1]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RI16(val)) + let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::INT) => { - let val = <[i32; 1]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RI32(val)) + let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RED, WebGlRenderingCtx::FLOAT) => { - let val = <[f32; 1]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RF32(val)) + let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RGB, WebGlRenderingCtx::UNSIGNED_BYTE) => { - let val = <[u8; 3]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RGBU8(val)) + let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RGBA, WebGlRenderingCtx::UNSIGNED_BYTE) => { - let val = <[u8; 4]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RGBAU8(val)) + let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } _ => Err(JsValue::from_str( "Pixel retrieval not implemented for that texture format.", @@ -336,21 +336,22 @@ impl Texture2D { #[cfg(feature = "webgl1")] let value = match (*format, *type_) { (WebGlRenderingCtx::LUMINANCE_ALPHA, WebGlRenderingCtx::FLOAT) => { - let val = <[f32; 1]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RF32(val)) + let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RGB, WebGlRenderingCtx::UNSIGNED_BYTE) => { - let val = <[u8; 3]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RGBU8(val)) + let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } (WebGlRenderingCtx::RGBA, WebGlRenderingCtx::UNSIGNED_BYTE) => { - let val = <[u8; 4]>::read_pixel(&self.gl, x, y)?; - Ok(PixelType::RGBAU8(val)) + let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?; + Ok(JsValue::from_serde(&p).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?) } _ => Err(JsValue::from_str( "Pixel retrieval not implemented for that texture format.", )), }; + // Unbind the framebuffer self.gl .bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, None); diff --git a/src/core/src/app.rs b/src/core/src/app.rs index 6e72203c..f4bd5984 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -11,7 +11,7 @@ use crate::{async_task::{TaskExecutor, BuildCatalogIndex, ParseTableTask, TaskRe }, shader::ShaderManager, survey::ImageSurveys, tile_fetcher::TileFetcherQueue, time::DeltaTime, utils}; use al_core::{ resources::Resources, - pixel::PixelType, WebGlContext + WebGlContext }; use al_api::{ @@ -381,7 +381,7 @@ pub trait AppTrait { // Setter of the meta data of a layer fn set_image_survey_color_cfg(&mut self, layer: String, meta: ImageSurveyMeta) -> Result<(), JsValue>; - fn read_pixel(&self, pos: &Vector2, base_url: &str) -> Result; + fn read_pixel(&self, pos: &Vector2, base_url: &str) -> Result; fn set_projection(self) -> App; //fn set_longitude_reversed(&mut self, longitude_reversed: bool); @@ -543,7 +543,7 @@ where } } else { let Allsky { image, time_req, .. } = allsky; - + { let mutex_locked = image.lock().unwrap(); let images = mutex_locked.as_ref(); @@ -614,12 +614,12 @@ where self.set_center(&self.get_center()); } - fn read_pixel(&self, pos: &Vector2, layer_id: &str) -> Result { + fn read_pixel(&self, pos: &Vector2, layer_id: &str) -> Result { if let Some(lonlat) = self.screen_to_world(pos) { let survey = self.surveys.get_from_layer(layer_id) .ok_or(JsValue::from_str(&format!("Did not found the survey {:?}", layer_id)))?; - survey.read_pixel(&lonlat) + survey.read_pixel(&lonlat, &self.camera) } else { Err(JsValue::from_str(&format!( "{:?} is out of projection", diff --git a/src/core/src/healpix/utils.rs b/src/core/src/healpix/utils.rs index a456a46c..6558ddcd 100644 --- a/src/core/src/healpix/utils.rs +++ b/src/core/src/healpix/utils.rs @@ -45,4 +45,8 @@ pub fn grid_lonlat(cell: &HEALPixCell, n_segments_by_side: u16) -> LonLatT::new(Angle(lon), Angle(lat)) }) .collect() +} + +pub fn hash_with_dxdy(depth: u8, lonlat: &LonLatT) -> (u64, f64, f64) { + healpix::nested::hash_with_dxdy(depth, lonlat.lon().0, lonlat.lat().0) } \ No newline at end of file diff --git a/src/core/src/survey/buffer.rs b/src/core/src/survey/buffer.rs index b13e5929..25193cbc 100644 --- a/src/core/src/survey/buffer.rs +++ b/src/core/src/survey/buffer.rs @@ -514,46 +514,43 @@ impl ImageSurveyTextures { self.heap.update_entry(tex_cell_item); } + // lonlat is given in the pub fn get_pixel_position_in_texture( &self, lonlat: &LonLatT, depth: u8, ) -> Result, JsValue> { - let (pix, dx, dy) = healpix::nested::hash_with_dxdy(depth, lonlat.lon().0, lonlat.lat().0); + let (pix, dx, dy) = crate::healpix::utils::hash_with_dxdy(depth, lonlat); + let texture_cell = HEALPixCell(depth, pix); - let cell = HEALPixCell(depth, pix); - // Index of the texture in the total set of textures - if let Some(texture) = self.textures.get(&cell) { + if let Some(texture) = self.textures.get(&texture_cell) { + let cfg = &self.config; + + // Index of the texture in the total set of textures let texture_idx = texture.idx(); // Index of the slice of textures - let idx_slice = texture_idx / self.config.num_textures_by_slice(); + let num_textures_by_slice = cfg.num_textures_by_slice(); + let idx_slice = texture_idx / num_textures_by_slice; // Index of the texture in its slice - let idx_in_slice = texture_idx % self.config.num_textures_by_slice(); + let idx_in_slice = texture_idx % num_textures_by_slice; // Index of the column of the texture in its slice - let idx_col_in_slice = idx_in_slice / self.config.num_textures_by_side_slice(); + let num_textures_by_side_slice = cfg.num_textures_by_side_slice(); + let idx_col_in_slice = idx_in_slice / num_textures_by_side_slice; // Index of the row of the texture in its slice - let idx_row_in_slice = idx_in_slice % self.config.num_textures_by_side_slice(); - - // Row and column indexes of the tile in its texture - let (idx_col_in_tex, idx_row_in_tex) = cell.get_offset_in_texture_cell(&self.config); + let idx_row_in_slice = idx_in_slice % num_textures_by_side_slice; // The size of the global texture containing the tiles - let texture_size = self.config.get_texture_size(); - // The size of a tile in its texture - let tile_size = self.config.get_tile_size(); + let texture_size = cfg.get_texture_size(); // Offset in the slice in pixels let mut offset = Vector3::new( - (idx_row_in_slice as i32) * texture_size - + (idx_row_in_tex as i32) * tile_size - + ((dy * (tile_size as f64)) as i32), - (idx_col_in_slice as i32) * texture_size - + (idx_col_in_tex as i32) * tile_size - + ((dx * (tile_size as f64)) as i32), + (idx_row_in_slice as i32) * texture_size + ((dy * (texture_size as f64)) as i32), + (idx_col_in_slice as i32) * texture_size + ((dx * (texture_size as f64)) as i32), idx_slice, ); + // Offset in the slice in pixels if self.config.tex_storing_fits { let mut uvy = offset.y as f32 / 4096.0; uvy = self.config.size_tile_uv @@ -567,7 +564,7 @@ impl ImageSurveyTextures { } else { Err(JsValue::from_str(&format!( "{:?} not loaded in the GPU, please wait before trying again.", - cell + texture_cell ))) } } diff --git a/src/core/src/survey/mod.rs b/src/core/src/survey/mod.rs index 756c2d1e..fb069105 100644 --- a/src/core/src/survey/mod.rs +++ b/src/core/src/survey/mod.rs @@ -487,7 +487,6 @@ use crate::{ }, }; -use al_core::pixel::PixelType; use web_sys::{WebGl2RenderingContext, WheelEvent}; use wasm_bindgen::JsCast; use al_core::{ @@ -496,6 +495,7 @@ use al_core::{ image::Image }; +use crate::math::lonlat::LonLat; impl ImageSurvey { fn new( config: HiPSConfig, @@ -652,11 +652,17 @@ impl ImageSurvey { self.view.reset_frame(); } - pub fn read_pixel(&self, pos: &LonLatT) -> Result { + // Position given is in the camera space + pub fn read_pixel(&self, pos: &LonLatT, camera: &CameraViewPort) -> Result { + // 1. Convert it to the hips frame system + let camera_frame = camera.get_system(); + let hips_frame = &self.get_config().get_frame(); + + let pos = crate::coosys::apply_coo_system(camera_frame, hips_frame, &pos.vector()); + // Get the array of textures from that survey - let pos_tex = self - .textures - .get_pixel_position_in_texture(pos, self.view.get_depth())?; + let pos_tex = self.textures + .get_pixel_position_in_texture(&pos.lonlat(), self.view.get_depth())?; let slice_idx = pos_tex.z as usize; let texture_array = self.textures.get_texture_array(); @@ -1079,10 +1085,10 @@ impl ImageSurveys { } } - pub fn read_pixel(&self, pos: &LonLatT, url: &Url) -> Result { + pub fn read_pixel(&self, pos: &LonLatT, url: &Url, camera: &CameraViewPort) -> Result { if let Some(survey) = self.surveys.get(url) { // Read the pixel from the first survey of layer - survey.read_pixel(pos) + survey.read_pixel(pos, camera) } else { Err(JsValue::from_str("No survey found")) } diff --git a/src/js/HpxImageSurvey.js b/src/js/HpxImageSurvey.js index 0247211c..5f846ae1 100644 --- a/src/js/HpxImageSurvey.js +++ b/src/js/HpxImageSurvey.js @@ -465,6 +465,11 @@ export let HpxImageSurvey = (function() { return this.meta.opacity; }; + // @api + HpxImageSurvey.prototype.readPixel = function(x, y) { + return this.backend.aladin.webglAPI.readPixel(x, y, this.layer); + }; + HpxImageSurvey.DEFAULT_SURVEY_ID = "P/DSS2/color"; HpxImageSurvey.SURVEYS_OBJECTS = {};