From 49061a746b54bf4485dc50158ee9104da617111d Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 11 Jun 2024 12:08:27 +0200 Subject: [PATCH 01/12] first commit --- CHANGELOG.md | 1 + examples/al-stcs-footprints.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff38331..f02990c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * [fixed] Change `RADECSYS` to `RADESYS` for `Aladin#getViewWCS` to follow fits standard deprecation * [feat] Add new method `Aladin#getViewImageBuffer` to get the current view as a PNG buffer +* [feat] New line rasterizer using GL instancing. ## 3.3.3 diff --git a/examples/al-stcs-footprints.html b/examples/al-stcs-footprints.html index 8a3c7a5e..d53b6004 100644 --- a/examples/al-stcs-footprints.html +++ b/examples/al-stcs-footprints.html @@ -11,7 +11,7 @@ A.init.then(() => { // Start up Aladin Lite - let aladin = A.aladin('#aladin-lite-div', {survey: "CDS/P/DSS2/color", target: 'Sgr a*', fov: 0.5, showContextMenu: true}); + let aladin = A.aladin('#aladin-lite-div', {survey: "CDS/P/DSS2/color", target: 'Sgr a*', fov: 0.5, showContextMenu: true, showCooGrid: true}); // This table contains a s_region column containing stcs expressed regions // that are automatically parsed aladin.addCatalog(A.catalogFromURL('https://aladin.cds.unistra.fr/AladinLite/doc/API/examples/data/alma-footprints.xml', {name: 'ALMA footprints', onClick: 'showTable', hoverColor: 'lightgreen'})); From 776cd3696955ff1fa8e4f0dccc126cb466f982cb Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Thu, 13 Jun 2024 17:26:59 +0200 Subject: [PATCH 02/12] use of instancing and impl inside the line rasterizer. Lyon is not needed anymore for plotting lines, but still used for plotting filled paths --- examples/al-gw.html | 2 +- examples/al-init-custom-options.html | 1 + .../src/object/array_buffer_instanced.rs | 56 +++++-- .../al-core/src/object/vertex_array_object.rs | 21 ++- src/core/src/renderable/catalog/manager.rs | 7 +- src/core/src/renderable/line/mod.rs | 152 ++++++++++++++++-- src/js/DefaultActionsForContextMenu.js | 2 +- src/js/MOC.js | 2 +- 8 files changed, 204 insertions(+), 39 deletions(-) diff --git a/examples/al-gw.html b/examples/al-gw.html index c09ab433..3b209720 100644 --- a/examples/al-gw.html +++ b/examples/al-gw.html @@ -14,7 +14,7 @@ A.init.then(() => { aladin = A.aladin('#aladin-lite-div', {showReticle: true, showSurveyStackControl: true, showOverlayStackControl: false, projection: "TAN", target: '15 16 57.636 -60 55 7.49', showProjectionControl: true, realFullscreen: true, showZoomControl: true, showSimbadPointerControl: true, showShareControl: true, showContextMenu: true, showCooGridControl: true, fullScreen: true, showCooGrid: true, fov: 90}); - var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 3, fill: false, perimeter: true}); + var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 10, fill: false, perimeter: true}); var moc_0_95 = A.MOCFromURL("./data/gw/gw_0.6.fits",{ name: "GW 60%", color: "#00ff00", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); var moc_0_5 = A.MOCFromURL("./data/gw/gw_0.3.fits",{ name: "GW 30%", color: "#00ffff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); var moc_0_2 = A.MOCFromURL("./data/gw/gw_0.1.fits",{ name: "GW 10%", color: "#ff00ff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); diff --git a/examples/al-init-custom-options.html b/examples/al-init-custom-options.html index 1b02b5d9..1dc96761 100644 --- a/examples/al-init-custom-options.html +++ b/examples/al-init-custom-options.html @@ -23,6 +23,7 @@ reticleColor: '#ff89ff', // change reticle color reticleSize: 64, // change reticle size showContextMenu: true, + showCooGrid: true, } ); }); diff --git a/src/core/al-core/src/object/array_buffer_instanced.rs b/src/core/al-core/src/object/array_buffer_instanced.rs index a6e5a0f0..f4f0d218 100644 --- a/src/core/al-core/src/object/array_buffer_instanced.rs +++ b/src/core/al-core/src/object/array_buffer_instanced.rs @@ -6,6 +6,7 @@ use crate::webgl_ctx::WebGlContext; pub struct ArrayBufferInstanced { buffer: WebGlBuffer, + len: usize, num_packed_data: usize, offset_idx: u32, @@ -39,7 +40,7 @@ impl ArrayBufferInstanced { offset_idx: u32, stride: usize, sizes: &[usize], - _offsets: &[usize], + offsets: &[usize], usage: u32, data: B, ) -> ArrayBufferInstanced { @@ -49,29 +50,43 @@ impl ArrayBufferInstanced { let num_f32_in_buf = data.len() as i32; let num_instances = num_f32_in_buf / (num_f32_per_instance as i32); + let len = data.len(); - let buffer = gl.create_buffer().ok_or("failed to create buffer").unwrap_abort(); + let buffer = gl + .create_buffer() + .ok_or("failed to create buffer") + .unwrap_abort(); // Bind the buffer gl.bind_buffer(WebGlRenderingCtx::ARRAY_BUFFER, Some(buffer.as_ref())); // Pass the vertices data to the buffer f32::buffer_data_with_array_buffer_view(gl, data, WebGlRenderingCtx::ARRAY_BUFFER, usage); // Link to the shader - let idx = offset_idx; + for (idx, (size, offset)) in sizes.iter().zip(offsets.iter()).enumerate() { + let idx = (idx as u32) + offset_idx; + + f32::vertex_attrib_pointer_with_i32( + gl, + idx, + *size as i32, + stride as i32, + *offset as i32, + ); - f32::vertex_attrib_pointer_with_i32(gl, idx, *sizes.first().unwrap_abort() as i32, 0, 0); - gl.enable_vertex_attrib_array(idx); + gl.enable_vertex_attrib_array(idx); - #[cfg(feature = "webgl2")] - gl.vertex_attrib_divisor(idx, 1); - #[cfg(feature = "webgl1")] - gl.ext.angles.vertex_attrib_divisor_angle(idx, 1); + #[cfg(feature = "webgl2")] + gl.vertex_attrib_divisor(idx, 1); + #[cfg(feature = "webgl1")] + gl.ext.angles.vertex_attrib_divisor_angle(idx, 1); + } let num_packed_data = sizes.len(); let gl = gl.clone(); // Returns an instance that keeps only the buffer ArrayBufferInstanced { buffer, + len, num_packed_data, offset_idx, @@ -119,13 +134,30 @@ impl ArrayBufferInstanced { self.gl.disable_vertex_attrib_array(loc as u32); } - pub fn update<'a, B: BufferDataStorage<'a, f32>>(&self, buffer: B) { + pub fn update<'a, B: BufferDataStorage<'a, f32>>(&mut self, usage: u32, data: B) { self.bind(); - f32::buffer_sub_data_with_i32_and_array_buffer_view( + if self.len >= data.len() { + f32::buffer_sub_data_with_i32_and_array_buffer_view( + &self.gl, + data, + WebGlRenderingCtx::ARRAY_BUFFER, + ); + } else { + self.len = data.len(); + + f32::buffer_data_with_array_buffer_view( + &self.gl, + data, + WebGlRenderingCtx::ARRAY_BUFFER, + usage, + ); + } + + /*f32::buffer_sub_data_with_i32_and_array_buffer_view( &self.gl, buffer, WebGlRenderingCtx::ARRAY_BUFFER, - ); + );*/ /*self.gl.buffer_sub_data_with_i32_and_array_buffer_view( WebGlRenderingCtx::ARRAY_BUFFER, 0, diff --git a/src/core/al-core/src/object/vertex_array_object.rs b/src/core/al-core/src/object/vertex_array_object.rs index e34f8595..87b91ba2 100644 --- a/src/core/al-core/src/object/vertex_array_object.rs +++ b/src/core/al-core/src/object/vertex_array_object.rs @@ -9,8 +9,8 @@ pub mod vao { use crate::object::element_array_buffer::ElementArrayBuffer; use crate::webgl_ctx::WebGlContext; - use std::collections::HashMap; use crate::Abort; + use std::collections::HashMap; pub struct VertexArrayObject { array_buffer: HashMap<&'static str, ArrayBuffer>, @@ -88,7 +88,10 @@ pub mod vao { }*/ pub fn num_elements(&self) -> usize { - self.element_array_buffer.as_ref().unwrap_abort().num_elements() + self.element_array_buffer + .as_ref() + .unwrap_abort() + .num_elements() } pub fn num_instances(&self) -> i32 { @@ -143,13 +146,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .unwrap_abort() - .update(array_data); + .update(usage, array_data); self } @@ -333,13 +337,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .unwrap_abort() - .update(array_data); + .update(usage, array_data); self } @@ -444,7 +449,10 @@ pub mod vao { }*/ pub fn num_elements(&self) -> usize { - self.element_array_buffer.as_ref().unwrap_abort().num_elements() + self.element_array_buffer + .as_ref() + .unwrap_abort() + .num_elements() } pub fn num_instances(&self) -> i32 { @@ -694,13 +702,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .expect("cannot get attribute from the array buffer") - .update(array_data); + .update(usage, array_data); self } diff --git a/src/core/src/renderable/catalog/manager.rs b/src/core/src/renderable/catalog/manager.rs index 409f2cc2..e21b54e3 100644 --- a/src/core/src/renderable/catalog/manager.rs +++ b/src/core/src/renderable/catalog/manager.rs @@ -26,6 +26,7 @@ impl From for JsValue { } } +// Num of shapes const _NUM_SHAPES: usize = 5; pub struct Manager { gl: WebGlContext, @@ -457,7 +458,11 @@ impl Catalog { #[cfg(feature = "webgl2")] self.vertex_array_object_catalog .bind_for_update() - .update_instanced_array("center", VecData(&sources)); + .update_instanced_array( + "center", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&sources), + ); } fn draw( diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index 751366b6..53fc8d7d 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -11,14 +11,11 @@ use super::Renderer; use al_api::color::ColorRGBA; use al_core::SliceData; -use lyon::algorithms::{ - math::point, - measure::{PathMeasurements, SampleType}, - path::Path, -}; +use lyon::algorithms::{math::point, path::Path}; struct Meta { color: ColorRGBA, + thickness: f32, off_indices: usize, num_indices: usize, } @@ -35,9 +32,16 @@ pub struct RasterizedLineRenderer { shader: Shader, vao: VertexArrayObject, + shader_line_instanced: Shader, + + vao_idx: usize, + vertices: Vec, indices: Vec, meta: Vec, + + instanced_line_vaos: Vec, + meta_instanced: Vec, } use wasm_bindgen::JsValue; @@ -68,6 +72,38 @@ impl RasterizedLineRenderer { include_str!("../../../../glsl/webgl2/line/line_vertex.glsl"), include_str!("../../../../glsl/webgl2/line/line_frag.glsl"), )?; + let shader_line_instanced = Shader::new( + &gl, + r#"#version 300 es + precision lowp float; + layout (location = 0) in vec2 p_a; + layout (location = 1) in vec2 p_b; + layout (location = 2) in vec2 vertex; + + out vec2 out_uv; + out vec3 out_p; + + uniform float u_width; + + void main() { + vec2 x_b = p_b - p_a; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y; + gl_Position = vec4(p, 0.f, 1.f); + }"#, + r#"#version 300 es + precision lowp float; + out vec4 color; + + uniform vec4 u_color; + + void main() { + // Multiply vertex color with texture color (in linear space). + // Linear color is written and blended in Framebuffer and converted to sRGB later + color = u_color; + }"#, + )?; let mut vao = VertexArrayObject::new(&gl); vao.bind_for_update() @@ -87,10 +123,17 @@ impl RasterizedLineRenderer { .unbind(); let meta = vec![]; + let meta_instanced = vec![]; let gl = gl.clone(); + + let instanced_line_vaos = vec![]; Ok(Self { gl, shader, + shader_line_instanced, + vao_idx: 0, + instanced_line_vaos, + meta_instanced, vao, meta, vertices, @@ -167,22 +210,57 @@ impl RasterizedLineRenderer { self.meta.push(Meta { off_indices, num_indices, + thickness: 1.0, color: color.clone(), }); } + fn create_instanced_vao(&mut self) { + let mut vao = VertexArrayObject::new(&self.gl); + + vao.bind_for_update() + // Store the cartesian position of the center of the source in the a instanced VBO + .add_instanced_array_buffer( + "ndc_pos", + 4 * std::mem::size_of::(), + &[2, 2], + &[0, 2 * std::mem::size_of::()], + WebGl2RenderingContext::DYNAMIC_DRAW, + SliceData(&[]), + ) + .add_array_buffer( + "vertices", + 2 * std::mem::size_of::(), + &[2], + &[0], + WebGl2RenderingContext::STATIC_DRAW, + SliceData(&[ + 0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32, + ]), + ) + // Set the element buffer + .add_element_buffer( + WebGl2RenderingContext::STATIC_DRAW, + SliceData(&[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16]), + ) + // Unbind the buffer + .unbind(); + + self.instanced_line_vaos.push(vao); + } + pub fn add_stroke_paths( &mut self, paths: impl Iterator>, thickness: f32, color: &ColorRGBA, - style: &Style, + _style: &Style, ) where T: AsRef<[[f32; 2]]>, { - let num_vertices = (self.vertices.len() / 2) as u32; + //let num_vertices = (self.vertices.len() / 2) as u32; - let mut path_builder = Path::builder(); + /*let mut path_builder = Path::builder(); match &style { Style::None => { @@ -268,17 +346,40 @@ impl RasterizedLineRenderer { .unwrap_abort(); } - let VertexBuffers { vertices, indices } = geometry; + let VertexBuffers { vertices, indices } = geometry;*/ + if self.vao_idx == self.instanced_line_vaos.len() { + // create a vao + self.create_instanced_vao(); + } - let num_indices = indices.len(); - let off_indices = self.indices.len(); + let vao = &mut self.instanced_line_vaos[self.vao_idx]; + self.vao_idx += 1; - self.vertices.extend(vertices.iter().flatten()); - self.indices.extend(indices.iter()); + let mut buf: Vec = vec![]; - self.meta.push(Meta { - off_indices, - num_indices, + for PathVertices { vertices } in paths { + let vertices = vertices.as_ref(); + let path_vertices_buf_iter = vertices + .iter() + .zip(vertices.iter().skip(1)) + .map(|(a, b)| [a[0], a[1], b[0], b[1]]) + .flatten(); + + buf.extend(path_vertices_buf_iter); + } + + vao.bind_for_update().update_instanced_array( + "ndc_pos", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&buf), + ); + + let num_instances = buf.len() / 4; + + self.meta_instanced.push(Meta { + off_indices: 0, + thickness, + num_indices: num_instances, color: color.clone(), }); } @@ -308,6 +409,21 @@ impl RasterizedLineRenderer { } //self.gl.enable(WebGl2RenderingContext::CULL_FACE); + + // draw the lines + let shader_bound = self.shader_line_instanced.bind(&self.gl); + for (idx, meta) in self.meta_instanced.iter().enumerate() { + let vao_bound = shader_bound + .attach_uniform("u_color", &meta.color) + .attach_uniform("u_width", &meta.thickness) + .bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]); + + vao_bound.draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + meta.num_indices as i32, + ); + } self.gl.disable(WebGl2RenderingContext::BLEND); Ok(()) @@ -318,8 +434,10 @@ impl Renderer for RasterizedLineRenderer { fn begin(&mut self) { self.vertices.clear(); self.indices.clear(); - self.meta.clear(); + + self.meta_instanced.clear(); + self.vao_idx = 0; } fn end(&mut self) { diff --git a/src/js/DefaultActionsForContextMenu.js b/src/js/DefaultActionsForContextMenu.js index 9915725a..3151d21b 100644 --- a/src/js/DefaultActionsForContextMenu.js +++ b/src/js/DefaultActionsForContextMenu.js @@ -164,7 +164,7 @@ export let DefaultActionsForContextMenu = (function () { files.forEach(file => { const url = URL.createObjectURL(file); - let moc = A.MOCFromURL(url, { name: file.name, fill: true, opacity: 0.4 }); + let moc = A.MOCFromURL(url, { name: file.name, edge: true }); a.addMOC(moc); }); }; diff --git a/src/js/MOC.js b/src/js/MOC.js index 4b04829d..46f9e8ae 100644 --- a/src/js/MOC.js +++ b/src/js/MOC.js @@ -36,7 +36,7 @@ export let MOC = (function() { * * @class * @constructs MOC - * @param {MOCOptions} options - Configuration options for the MOC. + * @param {MOCOptions} options - Configuration options for the MOC */ let MOC = function(options) { //this.order = undefined; From 8d9ca2e2b9bff8f5b7bcae9d815e2c8fa5e6e67f Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Thu, 20 Jun 2024 18:39:02 +0200 Subject: [PATCH 03/12] store shaders in the wasm, add a build:dbg vite bundle mode, projections on the gpu --- examples/al-customize-button.html | 21 -- examples/al-easy-access-vizier.html | 1 - package.json | 4 + src/core/Cargo.toml | 18 +- src/core/al-core/src/shader.rs | 40 +-- src/core/build.rs | 105 +++++++ src/core/src/app.rs | 12 +- src/core/src/camera/fov.rs | 15 +- src/core/src/camera/mod.rs | 4 +- src/core/src/camera/view_hpx_cells.rs | 8 +- src/core/src/camera/viewport.rs | 14 +- src/core/src/grid/label.rs | 2 +- src/core/src/grid/mod.rs | 11 +- src/core/src/healpix/utils.rs | 1 + src/core/src/lib.rs | 13 +- src/core/src/math/angle.rs | 6 +- src/core/src/math/lonlat.rs | 32 +-- src/core/src/math/projection/coo_space.rs | 29 +- .../src/math/projection/domain/basic/disk.rs | 8 +- .../math/projection/domain/basic/ellipse.rs | 74 ++--- .../math/projection/domain/basic/parabola.rs | 28 +- .../src/math/projection/domain/basic/rect.rs | 13 +- .../math/projection/domain/basic/triangle.rs | 37 ++- src/core/src/math/projection/domain/cod.rs | 31 ++- src/core/src/math/projection/domain/full.rs | 12 +- src/core/src/math/projection/domain/hpx.rs | 27 +- src/core/src/math/projection/domain/op.rs | 58 ++-- src/core/src/math/projection/domain/par.rs | 18 +- src/core/src/math/projection/domain/sdf.rs | 22 +- src/core/src/math/projection/mod.rs | 117 ++++---- src/core/src/math/sph_geom/region.rs | 4 +- src/core/src/renderable/coverage/moc.rs | 98 ++++--- src/core/src/renderable/hips/mod.rs | 62 +++-- src/core/src/renderable/image/mod.rs | 31 ++- .../src/renderable/line/great_circle_arc.rs | 112 +++----- src/core/src/renderable/line/mod.rs | 188 +++++++------ src/core/src/renderable/mod.rs | 15 +- src/core/src/shader.rs | 144 +++++----- src/glsl/webgl1/catalogs/aitoff.vert | 31 --- src/glsl/webgl1/catalogs/arc.vert | 29 -- src/glsl/webgl1/catalogs/catalog.frag | 14 - src/glsl/webgl1/catalogs/mercator.vert | 30 -- src/glsl/webgl1/catalogs/mollweide.vert | 29 -- src/glsl/webgl1/catalogs/ortho.frag | 18 -- src/glsl/webgl1/catalogs/ortho.vert | 29 -- src/glsl/webgl1/catalogs/tan.vert | 31 --- src/glsl/webgl1/colormaps/colormap.frag | 20 -- src/glsl/webgl1/colormaps/colormap.glsl | 12 - src/glsl/webgl1/colormaps/colormap.vert | 12 - src/glsl/webgl1/grid/grid_cpu.frag | 7 - src/glsl/webgl1/grid/grid_cpu.vert | 7 - src/glsl/webgl1/hips/color.glsl | 82 ------ src/glsl/webgl1/hips/projection.glsl | 158 ----------- src/glsl/webgl1/hips/rasterizer/color.frag | 23 -- .../rasterizer/grayscale_to_colormap.frag | 29 -- src/glsl/webgl1/hips/rasterizer/raster.vert | 41 --- src/glsl/webgl1/hips/raytracer/color.frag | 106 ------- .../hips/raytracer/grayscale_to_colormap.frag | 92 ------- src/glsl/webgl1/hips/raytracer/healpix.glsl | 20 -- src/glsl/webgl1/hips/raytracer/raytracer.vert | 13 - src/glsl/webgl1/hips/transfer_funcs.glsl | 41 --- src/glsl/webgl1/line/line_frag.glsl | 8 - src/glsl/webgl1/line/line_vertex.glsl | 17 -- src/glsl/webgl1/misc/text.frag | 16 -- src/glsl/webgl1/misc/text.vert | 32 --- .../webgl1/passes/post_fragment_100es.glsl | 25 -- src/glsl/webgl1/passes/post_vertex_100es.glsl | 9 - src/glsl/webgl1/text/text_frag.glsl | 17 -- src/glsl/webgl1/text/text_vertex.glsl | 24 -- src/glsl/webgl2/catalogs/aitoff.vert | 2 +- src/glsl/webgl2/catalogs/arc.vert | 2 +- src/glsl/webgl2/catalogs/healpix.vert | 3 +- src/glsl/webgl2/catalogs/mercator.vert | 3 +- src/glsl/webgl2/catalogs/mollweide.vert | 3 +- src/glsl/webgl2/catalogs/ortho.vert | 3 +- src/glsl/webgl2/catalogs/tan.vert | 3 +- src/glsl/webgl2/fits/{vert.glsl => base.vert} | 0 .../{frag_isampler.glsl => isampler.frag} | 0 .../fits/{frag_sampler.glsl => sampler.frag} | 0 .../{frag_usampler.glsl => usampler.frag} | 0 src/glsl/webgl2/grid/grid_cpu.frag | 13 - src/glsl/webgl2/grid/grid_cpu.vert | 8 - src/glsl/webgl2/hips/projection.glsl | 259 ------------------ src/glsl/webgl2/hips/rasterizer/raster.vert | 6 - src/glsl/webgl2/hips/raytracer/color.frag | 2 +- .../hips/raytracer/grayscale_to_colormap.frag | 2 +- .../raytracer/grayscale_to_colormap_i.frag | 2 +- .../raytracer/grayscale_to_colormap_u.frag | 2 +- src/glsl/webgl2/hips/raytracer/raytracer.vert | 4 +- .../webgl2/line/{line_frag.glsl => base.frag} | 11 +- .../line/{line_vertex.glsl => base.vert} | 6 +- src/glsl/webgl2/line/inst_lonlat.vert | 79 ++++++ src/glsl/webgl2/line/inst_ndc.vert | 17 ++ src/glsl/webgl2/misc/text.frag | 16 -- src/glsl/webgl2/misc/text.vert | 32 --- src/glsl/webgl2/projection/ait.glsl | 18 ++ .../healpix.glsl => projection/hpx.glsl} | 0 src/glsl/webgl2/projection/mer.glsl | 3 + src/glsl/webgl2/projection/mol.glsl | 26 ++ src/glsl/webgl2/projection/projection.glsl | 11 + src/glsl/webgl2/projection/sin.glsl | 4 + src/glsl/webgl2/projection/stg.glsl | 4 + src/glsl/webgl2/projection/tan.glsl | 3 + src/glsl/webgl2/projection/zea.glsl | 5 + src/js/ShadersWebGL1.js | 126 --------- src/js/ShadersWebGL2.js | 185 ------------- src/js/WebGL.js | 4 - 107 files changed, 974 insertions(+), 2350 deletions(-) create mode 100644 src/core/build.rs delete mode 100644 src/glsl/webgl1/catalogs/aitoff.vert delete mode 100644 src/glsl/webgl1/catalogs/arc.vert delete mode 100644 src/glsl/webgl1/catalogs/catalog.frag delete mode 100644 src/glsl/webgl1/catalogs/mercator.vert delete mode 100644 src/glsl/webgl1/catalogs/mollweide.vert delete mode 100644 src/glsl/webgl1/catalogs/ortho.frag delete mode 100644 src/glsl/webgl1/catalogs/ortho.vert delete mode 100644 src/glsl/webgl1/catalogs/tan.vert delete mode 100644 src/glsl/webgl1/colormaps/colormap.frag delete mode 100644 src/glsl/webgl1/colormaps/colormap.glsl delete mode 100644 src/glsl/webgl1/colormaps/colormap.vert delete mode 100644 src/glsl/webgl1/grid/grid_cpu.frag delete mode 100644 src/glsl/webgl1/grid/grid_cpu.vert delete mode 100644 src/glsl/webgl1/hips/color.glsl delete mode 100644 src/glsl/webgl1/hips/projection.glsl delete mode 100644 src/glsl/webgl1/hips/rasterizer/color.frag delete mode 100644 src/glsl/webgl1/hips/rasterizer/grayscale_to_colormap.frag delete mode 100644 src/glsl/webgl1/hips/rasterizer/raster.vert delete mode 100644 src/glsl/webgl1/hips/raytracer/color.frag delete mode 100644 src/glsl/webgl1/hips/raytracer/grayscale_to_colormap.frag delete mode 100644 src/glsl/webgl1/hips/raytracer/healpix.glsl delete mode 100644 src/glsl/webgl1/hips/raytracer/raytracer.vert delete mode 100644 src/glsl/webgl1/hips/transfer_funcs.glsl delete mode 100644 src/glsl/webgl1/line/line_frag.glsl delete mode 100644 src/glsl/webgl1/line/line_vertex.glsl delete mode 100644 src/glsl/webgl1/misc/text.frag delete mode 100644 src/glsl/webgl1/misc/text.vert delete mode 100644 src/glsl/webgl1/passes/post_fragment_100es.glsl delete mode 100644 src/glsl/webgl1/passes/post_vertex_100es.glsl delete mode 100644 src/glsl/webgl1/text/text_frag.glsl delete mode 100644 src/glsl/webgl1/text/text_vertex.glsl rename src/glsl/webgl2/fits/{vert.glsl => base.vert} (100%) rename src/glsl/webgl2/fits/{frag_isampler.glsl => isampler.frag} (100%) rename src/glsl/webgl2/fits/{frag_sampler.glsl => sampler.frag} (100%) rename src/glsl/webgl2/fits/{frag_usampler.glsl => usampler.frag} (100%) delete mode 100644 src/glsl/webgl2/grid/grid_cpu.frag delete mode 100644 src/glsl/webgl2/grid/grid_cpu.vert delete mode 100644 src/glsl/webgl2/hips/projection.glsl rename src/glsl/webgl2/line/{line_frag.glsl => base.frag} (65%) rename src/glsl/webgl2/line/{line_vertex.glsl => base.vert} (72%) create mode 100644 src/glsl/webgl2/line/inst_lonlat.vert create mode 100644 src/glsl/webgl2/line/inst_ndc.vert delete mode 100644 src/glsl/webgl2/misc/text.frag delete mode 100644 src/glsl/webgl2/misc/text.vert create mode 100644 src/glsl/webgl2/projection/ait.glsl rename src/glsl/webgl2/{hips/raytracer/healpix.glsl => projection/hpx.glsl} (100%) create mode 100644 src/glsl/webgl2/projection/mer.glsl create mode 100644 src/glsl/webgl2/projection/mol.glsl create mode 100644 src/glsl/webgl2/projection/projection.glsl create mode 100644 src/glsl/webgl2/projection/sin.glsl create mode 100644 src/glsl/webgl2/projection/stg.glsl create mode 100644 src/glsl/webgl2/projection/tan.glsl create mode 100644 src/glsl/webgl2/projection/zea.glsl delete mode 100644 src/js/ShadersWebGL1.js delete mode 100644 src/js/ShadersWebGL2.js diff --git a/examples/al-customize-button.html b/examples/al-customize-button.html index 7f4c6503..0e66b8b2 100644 --- a/examples/al-customize-button.html +++ b/examples/al-customize-button.html @@ -96,27 +96,6 @@ background-color: pink; } - - @media screen and (max-width:480px) { - /* smartphones, Android phones, landscape iPhone */ - .aladin-cooFrame { - top: unset; - position: absolute; - bottom: 0; - } - - .aladin-location { - left: 0.2rem; - } - - .aladin-fov { - left: 6rem; - } - - .aladin-projection-control { - display: none; - } - } diff --git a/examples/al-easy-access-vizier.html b/examples/al-easy-access-vizier.html index ab2d8b08..19134e62 100644 --- a/examples/al-easy-access-vizier.html +++ b/examples/al-easy-access-vizier.html @@ -26,7 +26,6 @@ aladin.addCatalog(A.catalogFromURL('https://vizier.u-strasbg.fr/viz-bin/votable?-source=HIP2&-c=LMC&-out.add=_RAJ,_DEJ&-oc.form=dm&-out.meta=DhuL&-out.max=9999&-c.rm=180', {sourceSize:12, color: '#f08080'})); - aladin.addCatalog(A.catalogFromURL(vmc_cepheids, {onClick: 'showTable', sourceSize:14, color: '#fff080'})); diff --git a/package.json b/package.json index 49c95f52..f00407af 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,15 @@ ], "scripts": { "wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2 -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ", + "wasm:dbg": "wasm-pack build --dev ./src/core --target web --out-name core -- --features=webgl2,dbg -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ", "predeploy": "npm run build && rm -rf aladin-lite*.tgz && npm pack", "deploy": "python3 deploy/deploy.py", "build": "npm run wasm && vite build && cp examples/index.html dist/index.html", + "build:dbg": "npm run wasm:dbg && vite build && cp examples/index.html dist/index.html", "dev": "npm run build && vite", + "dev:dbg": "npm run build:dbg && vite", "serve": "npm run dev", + "serve:dbg": "npm run dev:dbg", "preview": "vite preview", "test:build": "cd src/core && cargo test --release --features webgl2", "test:unit": "vitest run", diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index 19e14b61..4305fc52 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -30,10 +30,12 @@ fitsrs = "0.2.9" wcs = "0.2.8" colorgrad = "0.6.2" lyon = "1.0.1" +console_error_panic_hook = {version = "0.1.7", optional = true} [features] webgl1 = [ "al-core/webgl1", "al-api/webgl1", "web-sys/WebGlRenderingContext", "web-sys/AngleInstancedArrays", "web-sys/ExtSRgb", "web-sys/OesTextureFloat",] webgl2 = [ "al-core/webgl2", "al-api/webgl2", "web-sys/WebGl2RenderingContext", "web-sys/WebGlVertexArrayObject", "web-sys/ExtColorBufferFloat",] +dbg = ['dep:console_error_panic_hook'] [dev-dependencies] rand = "0.8" @@ -43,10 +45,6 @@ package = "cdshealpix" git = "https://github.com/cds-astro/cds-healpix-rust" branch = "master" -#[dependencies.moclib] -#package = "moc" -#version = "0.14.2" - [dependencies.moclib] package = "moc" #path = "../../../cds-moc-rust/" @@ -73,16 +71,12 @@ version = "0.24.2" default-features = false features = [ "jpeg", "png",] +[build-dependencies] +# Shader preprocessing +walkdir = "2.3.2" + [profile.dev] -opt-level = "z" debug = true -debug-assertions = true -overflow-checks = true -lto = true -panic = "unwind" -incremental = true -codegen-units = 256 -rpath = false [profile.release] opt-level = "z" diff --git a/src/core/al-core/src/shader.rs b/src/core/al-core/src/shader.rs index 026d091e..0f75a910 100644 --- a/src/core/al-core/src/shader.rs +++ b/src/core/al-core/src/shader.rs @@ -1,8 +1,8 @@ -use web_sys::{WebGlProgram, WebGlShader, WebGlUniformLocation}; use wasm_bindgen::JsValue; +use web_sys::{WebGlProgram, WebGlShader, WebGlUniformLocation}; -use crate::Colormaps; use crate::webgl_ctx::WebGlRenderingCtx; +use crate::Colormaps; fn compile_shader( gl: &WebGlContext, shader_type: u32, @@ -289,17 +289,6 @@ impl UniformType for TransferFunction { } } -/*use al_api::hips::GrayscaleParameter; -impl SendUniforms for GrayscaleParameter { - fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> { - shader - .attach_uniforms_from(&self.h) - .attach_uniform("min_value", &self.min_value) - .attach_uniform("max_value", &self.max_value); - - shader - } -}*/ use al_api::hips::HiPSColor; use al_api::hips::ImageMetadata; @@ -314,7 +303,7 @@ impl SendUniforms for ImageMetadata { } impl SendUniforms for HiPSColor { - fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> { + fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> { let reversed = self.reversed as u8 as f32; shader @@ -326,14 +315,17 @@ impl SendUniforms for HiPSColor { .attach_uniform("k_brightness", &self.k_brightness) .attach_uniform("k_contrast", &self.k_contrast) .attach_uniform("reversed", &reversed); - + shader } } - impl SendUniformsWithParams for HiPSColor { - fn attach_uniforms_with_params<'a>(&self, shader: &'a ShaderBound<'a>, cmaps: &Colormaps) -> &'a ShaderBound<'a> { + fn attach_uniforms_with_params<'a>( + &self, + shader: &'a ShaderBound<'a>, + cmaps: &Colormaps, + ) -> &'a ShaderBound<'a> { let reversed = self.reversed as u8 as f32; let cmap = cmaps.get(&self.cmap_name.as_ref()); @@ -347,7 +339,7 @@ impl SendUniformsWithParams for HiPSColor { .attach_uniform("k_brightness", &self.k_brightness) .attach_uniform("k_contrast", &self.k_contrast) .attach_uniform("reversed", &reversed); - + shader } } @@ -375,7 +367,11 @@ impl<'a> ShaderBound<'a> { self } - pub fn attach_uniforms_with_params_from>(&'a self, t: &T, params: &P) -> &'a Self { + pub fn attach_uniforms_with_params_from>( + &'a self, + t: &T, + params: &P, + ) -> &'a Self { t.attach_uniforms_with_params(self, params); self @@ -422,5 +418,9 @@ pub trait SendUniforms { } pub trait SendUniformsWithParams { - fn attach_uniforms_with_params<'a>(&self, shader: &'a ShaderBound<'a>, params: &T) -> &'a ShaderBound<'a>; + fn attach_uniforms_with_params<'a>( + &self, + shader: &'a ShaderBound<'a>, + params: &T, + ) -> &'a ShaderBound<'a>; } diff --git a/src/core/build.rs b/src/core/build.rs new file mode 100644 index 00000000..2750aed2 --- /dev/null +++ b/src/core/build.rs @@ -0,0 +1,105 @@ +use std::{error::Error, fs}; +use walkdir::WalkDir; +extern crate walkdir; +use std::io::BufRead; + +// All my shaders reside in the 'src/shaders' directory +fn generate_shaders() -> std::result::Result<(), Box> { + println!("generate shaders"); + let mut shaders = HashMap::new(); + + for entry in WalkDir::new("../glsl/webgl2/") + .into_iter() + .filter_map(|e| e.ok()) + { + if entry.file_type().is_file() { + let path = entry.path(); + if let Some(ext) = path.extension() { + if ext == "vert" || ext == "frag" { + let file_name = path.file_name().unwrap().to_str().unwrap(); + + let out_file_name = path + .strip_prefix("../glsl/webgl2/") + .unwrap() + //.with_extension("") + .to_string_lossy() + .to_owned() + .replace("/", "_"); + //let out_name = format!("{}/{}", OUT_PATH, out_file_name); + + let src = read_shader(path)?; + shaders.insert(out_file_name, src); + + //fs::write(&out_name, result)?; + println!("cargo:rerun-if-changed=src/shaders/{}", file_name); + } + } + } + } + + write("src/shaders.rs".into(), shaders)?; + + Ok(()) +} + +fn read_shader>(path: P) -> std::io::Result { + let path = path.as_ref(); + let file = fs::File::open(path.to_str().unwrap())?; + + let shader_src = std::io::BufReader::new(file) + .lines() + .flatten() + .map(|l| { + if l.starts_with("#include") { + let incl_file_names: Vec<_> = l.split_terminator(&[';', ' '][..]).collect(); + let incl_file_name_rel = incl_file_names[1]; + let incl_file_name = path.parent().unwrap().join(incl_file_name_rel); + + read_shader(incl_file_name.to_str().unwrap()).unwrap() + } else { + l + } + }) + .collect::>() + .join("\n"); + + Ok(shader_src) +} + +use std::collections::HashMap; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +pub fn write(path: PathBuf, entries: HashMap) -> Result<(), Box> { + let mut all_the_files = File::create(&path)?; + + writeln!(&mut all_the_files, r#"use std::collections::HashMap;"#,)?; + writeln!(&mut all_the_files, r#""#,)?; + writeln!(&mut all_the_files, r#"#[allow(dead_code)]"#,)?; + writeln!( + &mut all_the_files, + r#"pub fn get_all() -> HashMap<&'static str, &'static str> {{"#, + )?; + writeln!(&mut all_the_files, r#" let mut out = HashMap::new();"#,)?; + + for (name, content) in entries { + writeln!( + &mut all_the_files, + r##" out.insert("{name}", r#"{content}"#);"##, + )?; + } + + writeln!(&mut all_the_files, r#" out"#,)?; + writeln!(&mut all_the_files, r#"}}"#,)?; + + Ok(()) +} + +fn main() { + if let Err(err) = generate_shaders() { + // panic here for a nicer error message, otherwise it will + // be flattened to one line for some reason + panic!("Unable to generate shaders\n{}", err); + } +} diff --git a/src/core/src/app.rs b/src/core/src/app.rs index 285c99b8..c0f1a73d 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -957,6 +957,7 @@ impl App { &self.colormaps, &self.projection, )?; + use al_core::log::console_log; // Draw the catalog //let fbo_view = &self.fbo_view; @@ -974,14 +975,11 @@ impl App { // Ok(()) //})?; - self.grid.draw( - &self.camera, - &mut self.shaders, - &self.projection, - &mut self.line_renderer, - )?; + self.grid + .draw(&self.camera, &self.projection, &mut self.line_renderer)?; self.line_renderer.end(); - self.line_renderer.draw(&self.camera)?; + self.line_renderer + .draw(&mut self.shaders, &self.camera, &self.projection)?; //let dpi = self.camera.get_dpi(); //ui.draw(&gl, dpi)?; diff --git a/src/core/src/camera/fov.rs b/src/core/src/camera/fov.rs index bfe5db37..5a1a150b 100644 --- a/src/core/src/camera/fov.rs +++ b/src/core/src/camera/fov.rs @@ -6,16 +6,15 @@ use crate::math::sph_geom::region::{Intersection, PoleContained, Region}; use crate::math::{projection::Projection, sph_geom::bbox::BoundingBox}; use crate::LonLatT; - use crate::ProjectionType; use std::iter; fn ndc_to_world( - ndc_coo: &[XYNDC], + ndc_coo: &[XYNDC], ndc_to_clip: &Vector2, clip_zoom_factor: f64, projection: &ProjectionType, -) -> Option> { +) -> Option>> { // Deproject the FOV from ndc to the world space let mut world_coo = Vec::with_capacity(ndc_coo.len()); @@ -35,7 +34,7 @@ fn ndc_to_world( Some(world_coo) } -fn world_to_model(world_coo: &[XYZWWorld], w2m: &Matrix4) -> Vec { +fn world_to_model(world_coo: &[XYZWWorld], w2m: &Matrix4) -> Vec> { let mut model_coo = Vec::with_capacity(world_coo.len()); for w in world_coo.iter() { @@ -61,9 +60,9 @@ const NUM_VERTICES: usize = 4 + 2 * NUM_VERTICES_WIDTH + 2 * NUM_VERTICES_HEIGHT // This struct belongs to the CameraViewPort pub struct FieldOfView { // Vertices - ndc_vertices: Vec, - world_vertices: Option>, - model_vertices: Option>, + ndc_vertices: Vec>, + world_vertices: Option>>, + model_vertices: Option>>, reg: Region, } @@ -183,7 +182,7 @@ impl FieldOfView { } } - pub fn get_vertices(&self) -> Option<&Vec> { + pub fn get_vertices(&self) -> Option<&Vec>> { self.model_vertices.as_ref() } diff --git a/src/core/src/camera/mod.rs b/src/core/src/camera/mod.rs index 25097409..8a4e9932 100644 --- a/src/core/src/camera/mod.rs +++ b/src/core/src/camera/mod.rs @@ -1,7 +1,7 @@ pub mod viewport; use crate::math::lonlat::LonLat; use crate::math::projection::coo_space::XYZWModel; -pub use viewport::{CameraViewPort}; +pub use viewport::CameraViewPort; pub mod fov; pub use fov::FieldOfView; @@ -14,7 +14,7 @@ use crate::ProjectionType; pub fn build_fov_coverage( depth: u8, fov: &FieldOfView, - camera_center: &XYZWModel, + camera_center: &XYZWModel, camera_frame: CooSystem, frame: CooSystem, proj: &ProjectionType, diff --git a/src/core/src/camera/view_hpx_cells.rs b/src/core/src/camera/view_hpx_cells.rs index acd12a2f..5c78f4b7 100644 --- a/src/core/src/camera/view_hpx_cells.rs +++ b/src/core/src/camera/view_hpx_cells.rs @@ -32,7 +32,7 @@ impl ViewHpxCells { &mut self, camera_depth: u8, fov: &FieldOfView, - center: &XYZWModel, + center: &XYZWModel, camera_frame: CooSystem, proj: &ProjectionType, // survey frame @@ -50,7 +50,7 @@ impl ViewHpxCells { &mut self, camera_depth: u8, fov: &FieldOfView, - center: &XYZWModel, + center: &XYZWModel, camera_frame: CooSystem, proj: &ProjectionType, // survey frame @@ -70,7 +70,7 @@ impl ViewHpxCells { &mut self, camera_depth: u8, fov: &FieldOfView, - center: &XYZWModel, + center: &XYZWModel, camera_frame: CooSystem, proj: &ProjectionType, ) { @@ -140,7 +140,7 @@ impl HpxCells { &mut self, camera_depth: u8, fov: &FieldOfView, - center: &XYZWModel, + center: &XYZWModel, camera_frame: CooSystem, proj: &ProjectionType, ) { diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs index f54e6e3c..25cc9e7e 100644 --- a/src/core/src/camera/viewport.rs +++ b/src/core/src/camera/viewport.rs @@ -6,14 +6,17 @@ pub enum UserAction { Starting = 4, } +// Longitude reversed identity matrix +const ID_R: &Matrix4 = &Matrix4::new( + -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, +); + use super::{fov::FieldOfView, view_hpx_cells::ViewHpxCells}; use crate::healpix::cell::HEALPixCell; use crate::healpix::coverage::HEALPixCoverage; use crate::math::angle::ToAngle; use crate::math::{projection::coo_space::XYZWModel, projection::domain::sdf::ProjDef}; - - use cgmath::{Matrix4, Vector2}; pub struct CameraViewPort { // The field of view angle @@ -558,7 +561,7 @@ impl CameraViewPort { self.clip_zoom_factor } - pub fn get_vertices(&self) -> Option<&Vec> { + pub fn get_vertices(&self) -> Option<&Vec>> { self.fov.get_vertices() } @@ -654,11 +657,6 @@ impl CameraViewPort { } fn update_center(&mut self) { - // Longitude reversed identity matrix - const ID_R: &Matrix4 = &Matrix4::new( - -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, - ); - // The center position is on the 3rd column of the w2m matrix self.center = self.w2m.z; diff --git a/src/core/src/grid/label.rs b/src/core/src/grid/label.rs index 6d6f32dd..b5547a6f 100644 --- a/src/core/src/grid/label.rs +++ b/src/core/src/grid/label.rs @@ -26,7 +26,7 @@ pub enum LabelOptions { #[derive(Debug)] pub struct Label { // The position - pub position: XYScreen, + pub position: XYScreen, // the string content pub content: String, // in radians diff --git a/src/core/src/grid/mod.rs b/src/core/src/grid/mod.rs index 867db691..625ec615 100644 --- a/src/core/src/grid/mod.rs +++ b/src/core/src/grid/mod.rs @@ -7,6 +7,7 @@ use crate::math::projection::coo_space::XYScreen; use crate::Abort; use crate::camera::CameraViewPort; +use crate::coo_space::CooSpace; use crate::math::angle; use crate::math::HALF_PI; use crate::renderable::line; @@ -36,7 +37,6 @@ pub struct ProjetedGrid { parallels: Vec, } -use crate::shader::ShaderManager; use wasm_bindgen::JsValue; use crate::renderable::line::RasterizedLineRenderer; @@ -217,7 +217,13 @@ impl ProjetedGrid { .flatten() .map(|vertices| PathVertices { vertices }); - rasterizer.add_stroke_paths(paths, self.thickness, &self.color, &self.line_style); + rasterizer.add_stroke_paths( + paths, + self.thickness, + &self.color, + &self.line_style, + CooSpace::NDC, + ); Ok(()) } @@ -251,7 +257,6 @@ impl ProjetedGrid { pub fn draw( &mut self, camera: &CameraViewPort, - _shaders: &mut ShaderManager, projection: &ProjectionType, rasterizer: &mut RasterizedLineRenderer, ) -> Result<(), JsValue> { diff --git a/src/core/src/healpix/utils.rs b/src/core/src/healpix/utils.rs index 565347e7..05edc7c8 100644 --- a/src/core/src/healpix/utils.rs +++ b/src/core/src/healpix/utils.rs @@ -30,6 +30,7 @@ pub fn vertices_lonlat(cell: &HEALPixCell) -> [LonLatT; 4] { } use crate::Abort; /// Get the grid +#[allow(dead_code)] pub fn grid_lonlat(cell: &HEALPixCell, n_segments_by_side: u16) -> Vec> { debug_assert!(n_segments_by_side > 0); healpix::nested::grid(cell.depth(), cell.idx(), n_segments_by_side) diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 3a9437b5..8dacad8b 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -84,6 +84,7 @@ use crate::math::angle::ToAngle; mod app; pub mod async_task; mod camera; +mod shaders; mod coosys; mod downloader; @@ -139,8 +140,8 @@ pub struct WebClient { } use al_api::hips::ImageMetadata; +use al_core::log::console_log; use std::convert::TryInto; - #[wasm_bindgen] impl WebClient { /// Create the Aladin Lite webgl backend @@ -153,16 +154,18 @@ impl WebClient { #[wasm_bindgen(constructor)] pub fn new( aladin_div: &HtmlElement, - shaders: JsValue, + //_shaders: JsValue, resources: JsValue, ) -> Result { - //panic::set_hook(Box::new(console_error_panic_hook::hook)); + #[cfg(feature = "dbg")] + panic::set_hook(Box::new(console_error_panic_hook::hook)); - let shaders = serde_wasm_bindgen::from_value(shaders)?; + //let shaders = serde_wasm_bindgen::from_value(shaders)?; let resources = serde_wasm_bindgen::from_value(resources)?; let gl = WebGlContext::new(aladin_div)?; - let shaders = ShaderManager::new(&gl, shaders).unwrap_abort(); + let shaders = ShaderManager::new().unwrap_abort(); + console_log("jkjk2"); // Event listeners callbacks //let callback_position_changed = js_sys::Function::new_no_args(""); diff --git a/src/core/src/math/angle.rs b/src/core/src/math/angle.rs index 687b0a11..6bd271eb 100644 --- a/src/core/src/math/angle.rs +++ b/src/core/src/math/angle.rs @@ -244,7 +244,7 @@ pub enum SerializeFmt { DMS, HMS, DMM, - DD + DD, } use al_api::angle_fmt::AngleSerializeFmt; @@ -452,14 +452,14 @@ where pub trait ToAngle where - S: BaseFloat + S: BaseFloat, { fn to_angle(self) -> Angle; } impl ToAngle for S where - S: BaseFloat + S: BaseFloat, { fn to_angle(self) -> Angle { Angle(self) diff --git a/src/core/src/math/lonlat.rs b/src/core/src/math/lonlat.rs index 172823a4..f499d813 100644 --- a/src/core/src/math/lonlat.rs +++ b/src/core/src/math/lonlat.rs @@ -11,6 +11,7 @@ pub trait LonLat { use crate::math::angle::Angle; #[derive(Clone, Copy, Debug)] +#[repr(C)] pub struct LonLatT(pub Angle, pub Angle); impl LonLatT @@ -107,11 +108,10 @@ where let theta = lonlat.lon(); let delta = lonlat.lat(); - Vector3::::new( - delta.cos() * theta.sin(), - delta.sin(), - delta.cos() * theta.cos(), - ) + let (dc, ds) = (delta.cos(), delta.sin()); + let (tc, ts) = (theta.cos(), theta.sin()); + + Vector3::::new(dc * ts, ds, dc * tc) } } @@ -180,19 +180,17 @@ pub fn xyzw_to_radec(v: &Vector4) -> (Angle, Angle) { #[inline] pub fn radec_to_xyz(theta: Angle, delta: Angle) -> Vector3 { - Vector3::::new( - delta.cos() * theta.sin(), - delta.sin(), - delta.cos() * theta.cos(), - ) + let (dc, ds) = (delta.cos(), delta.sin()); + let (tc, ts) = (theta.cos(), theta.sin()); + + Vector3::::new(dc * ts, ds, dc * tc) } #[inline] pub fn radec_to_xyzw(theta: Angle, delta: Angle) -> Vector4 { - let (dc, ds) = (delta.cos(), delta.sin()); - let (tc, ts) = (theta.cos(), theta.sin()); + let xyz = radec_to_xyz(theta, delta); - Vector4::::new(dc * ts, ds, dc * tc, S::one()) + Vector4::::new(xyz.x, xyz.y, xyz.z, S::one()) } #[inline] @@ -223,14 +221,14 @@ pub fn proj( lonlat: &LonLatT, projection: &ProjectionType, camera: &CameraViewPort, -) -> Option { +) -> Option> { let xyzw = lonlat.vector(); projection.model_to_normalized_device_space(&xyzw, camera) } #[inline] pub fn unproj( - ndc_xy: &XYNDC, + ndc_xy: &XYNDC, projection: &ProjectionType, camera: &CameraViewPort, ) -> Option> { @@ -244,14 +242,14 @@ pub fn proj_to_screen( lonlat: &LonLatT, projection: &ProjectionType, camera: &CameraViewPort, -) -> Option { +) -> Option> { let xyzw = lonlat.vector(); projection.model_to_screen_space(&xyzw, camera) } #[inline] pub fn unproj_from_screen( - xy: &XYScreen, + xy: &XYScreen, projection: &ProjectionType, camera: &CameraViewPort, ) -> Option> { diff --git a/src/core/src/math/projection/coo_space.rs b/src/core/src/math/projection/coo_space.rs index 7e7402e9..af8fd9aa 100644 --- a/src/core/src/math/projection/coo_space.rs +++ b/src/core/src/math/projection/coo_space.rs @@ -1,13 +1,18 @@ -use cgmath::{ - Vector2, - Vector3, - Vector4, -}; +use cgmath::{Vector2, Vector3, Vector4}; -pub type XYScreen = Vector2; -pub type XYNDC = Vector2; -pub type XYClip = Vector2; -pub type XYZWorld = Vector3; -pub type XYZWWorld = Vector4; -pub type XYZWModel = Vector4; -pub type XYZModel = Vector3; \ No newline at end of file +pub type XYScreen = Vector2; +pub type XYNDC = Vector2; +pub type XYClip = Vector2; +pub type XYZWorld = Vector3; +pub type XYZModel = Vector3; +pub type XYZWWorld = Vector4; +pub type XYZWModel = Vector4; + +pub enum CooSpace { + Screen, + NDC, + Clip, + World, + Model, + LonLat, +} diff --git a/src/core/src/math/projection/domain/basic/disk.rs b/src/core/src/math/projection/domain/basic/disk.rs index 3564f91f..be64bfcc 100644 --- a/src/core/src/math/projection/domain/basic/disk.rs +++ b/src/core/src/math/projection/domain/basic/disk.rs @@ -1,14 +1,14 @@ use crate::math::projection::coo_space::XYClip; pub struct Disk { - pub radius: f64 + pub radius: f64, } -use cgmath::InnerSpace; use super::super::sdf::ProjDef; +use cgmath::InnerSpace; impl ProjDef for Disk { - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { xy.magnitude() - self.radius } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/basic/ellipse.rs b/src/core/src/math/projection/domain/basic/ellipse.rs index 4b8adca5..1c12cd76 100644 --- a/src/core/src/math/projection/domain/basic/ellipse.rs +++ b/src/core/src/math/projection/domain/basic/ellipse.rs @@ -8,13 +8,13 @@ pub struct Ellipse { pub b: f64, } -use cgmath::InnerSpace; use super::super::sdf::ProjDef; +use cgmath::InnerSpace; impl ProjDef for Ellipse { - fn sdf(&self, xy: &XYClip) -> f64 { - let mut p = Vector2::new( xy.x.abs(), xy.y.abs() ); - let mut ab = Vector2::new( self.a, self.b ); + fn sdf(&self, xy: &XYClip) -> f64 { + let mut p = Vector2::new(xy.x.abs(), xy.y.abs()); + let mut ab = Vector2::new(self.a, self.b); let sdf = if p.x == 0.0 { -(self.b - p.y) @@ -25,44 +25,44 @@ impl ProjDef for Ellipse { p = Vector2::new(p.y, p.x); ab = Vector2::new(ab.y, ab.x); } - - let l = ab.y*ab.y - ab.x*ab.x; - let m = ab.x*p.x/l; - let m2 = m*m; - let n = ab.y*p.y/l; - let n2 = n*n; - let c = (m2 + n2 - 1.0)/3.0; - let c3 = c*c*c; - let q = c3 + m2*n2*2.0; - let d = c3 + m2*n2; - let g = m + m*n2; - + + let l = ab.y * ab.y - ab.x * ab.x; + let m = ab.x * p.x / l; + let m2 = m * m; + let n = ab.y * p.y / l; + let n2 = n * n; + let c = (m2 + n2 - 1.0) / 3.0; + let c3 = c * c * c; + let q = c3 + m2 * n2 * 2.0; + let d = c3 + m2 * n2; + let g = m + m * n2; + let co = if d < 0.0 { - let p = (q/c3).acos()/3.0; + let p = (q / c3).acos() / 3.0; let s = p.cos(); - let t = p.sin()*(3.0_f64).sqrt(); - let rx = ( -c*(s + t + 2.0) + m2 ).sqrt(); - let ry = ( -c*(s - t + 2.0) + m2 ).sqrt(); - - ( ry + (l).signum()*rx + ((g).abs()/(rx*ry)) - m)/2.0 + let t = p.sin() * (3.0_f64).sqrt(); + let rx = (-c * (s + t + 2.0) + m2).sqrt(); + let ry = (-c * (s - t + 2.0) + m2).sqrt(); + + (ry + (l).signum() * rx + ((g).abs() / (rx * ry)) - m) / 2.0 } else { - let h = 2.0*m*n*(( d ).sqrt()); - let s = (q+h).signum()*( (q+h).abs() ).powf( 1.0/3.0 ); - let u = (q-h).signum()*( (q-h).abs() ).powf( 1.0/3.0 ); - let rx = -s - u - c*4.0 + 2.0*m2; - let ry = (s - u)*(3.0_f64).sqrt(); - - let rm = ( rx*rx + ry*ry ).sqrt(); - let p = ry/((rm-rx).sqrt()); - (p + (2.0*g/rm) - m)/2.0 + let h = 2.0 * m * n * ((d).sqrt()); + let s = (q + h).signum() * ((q + h).abs()).powf(1.0 / 3.0); + let u = (q - h).signum() * ((q - h).abs()).powf(1.0 / 3.0); + let rx = -s - u - c * 4.0 + 2.0 * m2; + let ry = (s - u) * (3.0_f64).sqrt(); + + let rm = (rx * rx + ry * ry).sqrt(); + let p = ry / ((rm - rx).sqrt()); + (p + (2.0 * g / rm) - m) / 2.0 }; - - let si = ( 1.0 - co*co ).sqrt(); - let q = Vector2::new( ab.x*co, ab.y*si ); - - (q-p).magnitude() * (p.y-q.y).signum() + + let si = (1.0 - co * co).sqrt(); + let q = Vector2::new(ab.x * co, ab.y * si); + + (q - p).magnitude() * (p.y - q.y).signum() }; sdf } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/basic/parabola.rs b/src/core/src/math/projection/domain/basic/parabola.rs index 3b29ef27..3a66cfdf 100644 --- a/src/core/src/math/projection/domain/basic/parabola.rs +++ b/src/core/src/math/projection/domain/basic/parabola.rs @@ -3,14 +3,14 @@ use crate::math::projection::coo_space::XYClip; use cgmath::Vector2; pub struct Parabola { // Quadratic coefficient - pub k: f64 + pub k: f64, } use super::super::sdf::ProjDef; use cgmath::InnerSpace; impl ProjDef for Parabola { - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let mut xy = *xy; // There is a singularity around x == 0 @@ -20,21 +20,17 @@ impl ProjDef for Parabola { xy.x += 1e-4; } xy.x = xy.x.abs(); - let ik = 1.0/self.k; - let p = ik*(xy.y - 0.5*ik)/3.0; - let q = 0.25*ik*ik*xy.x; - let h = q*q - p*p*p; + let ik = 1.0 / self.k; + let p = ik * (xy.y - 0.5 * ik) / 3.0; + let q = 0.25 * ik * ik * xy.x; + let h = q * q - p * p * p; let r = h.abs().sqrt(); - let x = if h>0.0 { - (q+r).powf(1.0/3.0) - (q-r).abs().powf(1.0/3.0)*(r-q).signum() + let x = if h > 0.0 { + (q + r).powf(1.0 / 3.0) - (q - r).abs().powf(1.0 / 3.0) * (r - q).signum() } else { - 2.0*(r.atan2(q)/3.0).cos()*p.sqrt() + 2.0 * (r.atan2(q) / 3.0).cos() * p.sqrt() }; - let a = if xy.x - x < 0.0 { - -1.0 - } else { - 1.0 - }; - (xy-Vector2::new(x, self.k*x*x)).magnitude() * a + let a = if xy.x - x < 0.0 { -1.0 } else { 1.0 }; + (xy - Vector2::new(x, self.k * x * x)).magnitude() * a } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/basic/rect.rs b/src/core/src/math/projection/domain/basic/rect.rs index 94c26beb..97c946a0 100644 --- a/src/core/src/math/projection/domain/basic/rect.rs +++ b/src/core/src/math/projection/domain/basic/rect.rs @@ -2,22 +2,19 @@ use crate::math::projection::coo_space::XYClip; use cgmath::Vector2; pub struct Rect { - pub dim: Vector2 + pub dim: Vector2, } use super::super::sdf::ProjDef; use cgmath::InnerSpace; impl ProjDef for Rect { - fn sdf(&self, xy: &XYClip) -> f64 { - let d = Vector2::new( - xy.x.abs() - self.dim.x, - xy.y.abs() - self.dim.y - ); + fn sdf(&self, xy: &XYClip) -> f64 { + let d = Vector2::new(xy.x.abs() - self.dim.x, xy.y.abs() - self.dim.y); let a = Vector2::new(d.x.max(0.0), d.y.max(0.0)); let b = (d.x.max(d.y)).min(0.0); - + a.magnitude() + b } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/basic/triangle.rs b/src/core/src/math/projection/domain/basic/triangle.rs index 906d57fe..ece8c3fc 100644 --- a/src/core/src/math/projection/domain/basic/triangle.rs +++ b/src/core/src/math/projection/domain/basic/triangle.rs @@ -10,30 +10,27 @@ pub struct Triangle { use super::super::sdf::ProjDef; use cgmath::InnerSpace; impl ProjDef for Triangle { - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let e0 = self.p1 - self.p0; let e1 = self.p2 - self.p1; let e2 = self.p0 - self.p2; - + let v0 = xy - self.p0; let v1 = xy - self.p1; let v2 = xy - self.p2; - - let pq0 = v0 - e0 * ( v0.dot(e0) / e0.dot(e0) ).clamp( 0.0, 1.0 ); - let pq1 = v1 - e1 * ( v1.dot(e1) / e1.dot(e1) ).clamp( 0.0, 1.0 ); - let pq2 = v2 - e2 * ( v2.dot(e2) / e2.dot(e2) ).clamp( 0.0, 1.0 ); - - let s = e0.x*e2.y - e0.y*e2.x; - - let d1 = Vector2::new(pq0.dot( pq0 ), s*(v0.x*e0.y-v0.y*e0.x)); - let d2 = Vector2::new(pq1.dot( pq1 ), s*(v1.x*e1.y-v1.y*e1.x)); - let d3 = Vector2::new(pq2.dot( pq2 ), s*(v2.x*e2.y-v2.y*e2.x)); - - let d = Vector2::new( - d1.x.min(d2.x.min(d3.x)), - d1.y.min(d2.y.min(d3.y)) - ); - - -d.x.sqrt()*(d.y.signum()) + + let pq0 = v0 - e0 * (v0.dot(e0) / e0.dot(e0)).clamp(0.0, 1.0); + let pq1 = v1 - e1 * (v1.dot(e1) / e1.dot(e1)).clamp(0.0, 1.0); + let pq2 = v2 - e2 * (v2.dot(e2) / e2.dot(e2)).clamp(0.0, 1.0); + + let s = e0.x * e2.y - e0.y * e2.x; + + let d1 = Vector2::new(pq0.dot(pq0), s * (v0.x * e0.y - v0.y * e0.x)); + let d2 = Vector2::new(pq1.dot(pq1), s * (v1.x * e1.y - v1.y * e1.x)); + let d3 = Vector2::new(pq2.dot(pq2), s * (v2.x * e2.y - v2.y * e2.x)); + + let d = Vector2::new(d1.x.min(d2.x.min(d3.x)), d1.y.min(d2.y.min(d3.y))); + + -d.x.sqrt() * (d.y.signum()) } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/cod.rs b/src/core/src/math/projection/domain/cod.rs index 9505dad3..c030c56e 100644 --- a/src/core/src/math/projection/domain/cod.rs +++ b/src/core/src/math/projection/domain/cod.rs @@ -1,16 +1,13 @@ use crate::math::projection::coo_space::XYClip; use cgmath::Vector2; -use crate::math::HALF_PI; -use crate::math::angle::PI; use super::{ - sdf::ProjDef, + basic::{ellipse::Ellipse, triangle::Triangle}, op::{Diff, Translate}, - basic::{ - triangle::Triangle, - ellipse::Ellipse, - } + sdf::ProjDef, }; +use crate::math::angle::PI; +use crate::math::HALF_PI; pub struct Cod { pub r_max: f64, @@ -41,7 +38,7 @@ impl Cod { } } - fn to_clip(&self, xy: &Vector2) -> XYClip { + fn to_clip(&self, xy: &Vector2) -> XYClip { let x = (xy.x - self.x_min) / (self.x_max - self.x_min); let y = (xy.y - self.y_min) / (self.y_max - self.y_min); @@ -50,20 +47,26 @@ impl Cod { } impl ProjDef for Cod { - fn sdf(&self, xy: &XYClip) -> f64 { - let y_mean = (self.y_min + self.y_max)*0.5; + fn sdf(&self, xy: &XYClip) -> f64 { + let y_mean = (self.y_min + self.y_max) * 0.5; let center_ellipse = self.to_clip(&Vector2::new(0.0, self.y0 + y_mean)); // Big frontier ellipse let a = 1.0; let b = 2.0 * (2.356194490192345 + self.y0) / (2.356194490192345 + 3.0328465566001492); let e = b / a; - let ext_ellipse = Translate { off: center_ellipse, def: Ellipse { a: a, b: b } }; + let ext_ellipse = Translate { + off: center_ellipse, + def: Ellipse { a: a, b: b }, + }; // Small ellipse where projection is not defined let b_int = 2.0 * self.r_min / (2.356194490192345 + 3.0328465566001492); let a_int = b_int / e; - let int_ellipse = Translate { off: center_ellipse, def: Ellipse { a: a_int, b: b_int } }; + let int_ellipse = Translate { + off: center_ellipse, + def: Ellipse { a: a_int, b: b_int }, + }; // The top edges let gamma = PI * self.c - HALF_PI; @@ -75,9 +78,9 @@ impl ProjDef for Cod { let tri = Triangle { p0: center_ellipse, p1: self.to_clip(&b), - p2: self.to_clip(&c) + p2: self.to_clip(&c), }; Diff::new(Diff::new(ext_ellipse, int_ellipse), tri).sdf(xy) } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/full.rs b/src/core/src/math/projection/domain/full.rs index 0ecb5d0b..2dc4cd67 100644 --- a/src/core/src/math/projection/domain/full.rs +++ b/src/core/src/math/projection/domain/full.rs @@ -3,12 +3,12 @@ use cgmath::Vector2; pub struct FullScreen; -use super::{ - basic::rect::Rect, - sdf::ProjDef, -}; +use super::{basic::rect::Rect, sdf::ProjDef}; impl ProjDef for FullScreen { - fn sdf(&self, xy: &XYClip) -> f64 { - Rect { dim: Vector2::new(1.0, 1.0) }.sdf(xy) + fn sdf(&self, xy: &XYClip) -> f64 { + Rect { + dim: Vector2::new(1.0, 1.0), + } + .sdf(xy) } } diff --git a/src/core/src/math/projection/domain/hpx.rs b/src/core/src/math/projection/domain/hpx.rs index a41a940f..df755ebe 100644 --- a/src/core/src/math/projection/domain/hpx.rs +++ b/src/core/src/math/projection/domain/hpx.rs @@ -5,58 +5,57 @@ pub struct Hpx; use super::sdf::ProjDef; use super::{ + basic::{rect::Rect, triangle::Triangle}, op::Union, - basic::{ - triangle::Triangle, - rect::Rect - } }; impl ProjDef for Hpx { - fn sdf(&self, xy: &XYClip) -> f64 { - let rect = Rect { dim: Vector2::new(1.0, 0.5) }; + fn sdf(&self, xy: &XYClip) -> f64 { + let rect = Rect { + dim: Vector2::new(1.0, 0.5), + }; let t1 = Triangle { p0: Vector2::new(1.0, 0.5), p1: Vector2::new(0.5, 0.5), - p2: Vector2::new(0.75, 1.0) + p2: Vector2::new(0.75, 1.0), }; let t2 = Triangle { p0: Vector2::new(0.5, 0.5), p1: Vector2::new(0.0, 0.5), - p2: Vector2::new(0.25, 1.0) + p2: Vector2::new(0.25, 1.0), }; let t3 = Triangle { p0: Vector2::new(-1.0, 0.5), p1: Vector2::new(-0.5, 0.5), - p2: Vector2::new(-0.75, 1.0) + p2: Vector2::new(-0.75, 1.0), }; let t4 = Triangle { p0: Vector2::new(-0.5, 0.5), p1: Vector2::new(-0.0, 0.5), - p2: Vector2::new(-0.25, 1.0) + p2: Vector2::new(-0.25, 1.0), }; let t5 = Triangle { p0: Vector2::new(-1.0, -0.5), p1: Vector2::new(-0.5, -0.5), - p2: Vector2::new(-0.75, -1.0) + p2: Vector2::new(-0.75, -1.0), }; let t6 = Triangle { p0: Vector2::new(-0.5, -0.5), p1: Vector2::new(-0.0, -0.5), - p2: Vector2::new(-0.25, -1.0) + p2: Vector2::new(-0.25, -1.0), }; let t7 = Triangle { p0: Vector2::new(1.0, -0.5), p1: Vector2::new(0.5, -0.5), - p2: Vector2::new(0.75, -1.0) + p2: Vector2::new(0.75, -1.0), }; let t8 = Triangle { p0: Vector2::new(0.5, -0.5), p1: Vector2::new(0.0, -0.5), - p2: Vector2::new(0.25, -1.0) + p2: Vector2::new(0.25, -1.0), }; let t12 = Union::new(t1, t2); diff --git a/src/core/src/math/projection/domain/op.rs b/src/core/src/math/projection/domain/op.rs index b590e91c..79fd11ea 100644 --- a/src/core/src/math/projection/domain/op.rs +++ b/src/core/src/math/projection/domain/op.rs @@ -1,10 +1,10 @@ +use super::sdf::ProjDef; use crate::math::projection::XYClip; use cgmath::Vector2; -use super::sdf::ProjDef; pub struct Scale where - T: ProjDef + T: ProjDef, { pub scale: Vector2, pub def: T, @@ -12,17 +12,18 @@ where impl ProjDef for Scale where - T: ProjDef + T: ProjDef, { /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64 { - self.def.sdf(&Vector2::new(xy.x / self.scale.x, xy.y / self.scale.y)) + fn sdf(&self, xy: &XYClip) -> f64 { + self.def + .sdf(&Vector2::new(xy.x / self.scale.x, xy.y / self.scale.y)) } } pub struct Translate where - T: ProjDef + T: ProjDef, { pub off: Vector2, pub def: T, @@ -30,10 +31,10 @@ where impl ProjDef for Translate where - T: ProjDef + T: ProjDef, { /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { self.def.sdf(&(*xy - self.off)) } } @@ -42,7 +43,7 @@ where pub struct Union where T: ProjDef, - U: ProjDef + U: ProjDef, { sdf1: T, sdf2: U, @@ -51,23 +52,20 @@ where impl Union where T: ProjDef, - U: ProjDef + U: ProjDef, { pub fn new(sdf1: T, sdf2: U) -> Self { - Self { - sdf1, - sdf2, - } + Self { sdf1, sdf2 } } } impl ProjDef for Union where T: ProjDef, - U: ProjDef + U: ProjDef, { /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let s1 = self.sdf1.sdf(xy); let s2 = self.sdf2.sdf(xy); @@ -79,7 +77,7 @@ where pub struct Inter where T: ProjDef, - U: ProjDef + U: ProjDef, { sdf1: T, sdf2: U, @@ -88,23 +86,20 @@ where impl Inter where T: ProjDef, - U: ProjDef + U: ProjDef, { pub fn new(sdf1: T, sdf2: U) -> Self { - Self { - sdf1, - sdf2, - } + Self { sdf1, sdf2 } } } impl ProjDef for Inter where T: ProjDef, - U: ProjDef + U: ProjDef, { /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let s1 = self.sdf1.sdf(xy); let s2 = self.sdf2.sdf(xy); @@ -116,7 +111,7 @@ where pub struct Diff where T: ProjDef, - U: ProjDef + U: ProjDef, { sdf1: T, sdf2: U, @@ -125,27 +120,24 @@ where impl Diff where T: ProjDef, - U: ProjDef + U: ProjDef, { pub fn new(sdf1: T, sdf2: U) -> Self { - Self { - sdf1, - sdf2, - } + Self { sdf1, sdf2 } } } impl ProjDef for Diff where T: ProjDef, - U: ProjDef + U: ProjDef, { /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let s1 = self.sdf1.sdf(xy); let s2 = self.sdf2.sdf(xy); // intersection (-s2).max(s1) } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/par.rs b/src/core/src/math/projection/domain/par.rs index 29c74d14..9b89f741 100644 --- a/src/core/src/math/projection/domain/par.rs +++ b/src/core/src/math/projection/domain/par.rs @@ -4,17 +4,23 @@ use cgmath::Vector2; pub struct Par; use super::{ - sdf::ProjDef, basic::parabola::Parabola, - op::{Translate, Inter} + op::{Inter, Translate}, + sdf::ProjDef, }; impl ProjDef for Par { - fn sdf(&self, xy: &XYClip) -> f64 { + fn sdf(&self, xy: &XYClip) -> f64 { let xy = Vector2::new(xy.y, xy.x); - let p1 = Translate { off: Vector2::new(0.0, -1.0), def: Parabola { k: 1.0 } }; - let p2 = Translate { off: Vector2::new(0.0, 1.0), def: Parabola { k: -1.0 } }; + let p1 = Translate { + off: Vector2::new(0.0, -1.0), + def: Parabola { k: 1.0 }, + }; + let p2 = Translate { + off: Vector2::new(0.0, 1.0), + def: Parabola { k: -1.0 }, + }; Inter::new(p1, p2).sdf(&xy) } -} \ No newline at end of file +} diff --git a/src/core/src/math/projection/domain/sdf.rs b/src/core/src/math/projection/domain/sdf.rs index b45a78c3..f5b6d252 100644 --- a/src/core/src/math/projection/domain/sdf.rs +++ b/src/core/src/math/projection/domain/sdf.rs @@ -3,28 +3,28 @@ use crate::math::projection::coo_space::XYClip; #[enum_dispatch(ProjDefType)] pub trait ProjDef { - fn is_in(&self, xy: &XYClip) -> bool { + fn is_in(&self, xy: &XYClip) -> bool { self.sdf(xy) <= 0.0 } /// Signed distance function to the definition domain region - fn sdf(&self, xy: &XYClip) -> f64; + fn sdf(&self, xy: &XYClip) -> f64; } use crate::math::vector::NormedVector2; /// Project a vertex on a valid region defined by a Signed Distance Function (SDF) -/// +/// /// # Arguments /// -/// * `p` - A vertex in the clipping space +/// * `p` - A vertex in the clipping space /// * `dir` - A direction of the normed vector /// * `valid_reg` - The projection definition region -pub fn ray_marching

(p: &XYClip, dir: &NormedVector2, valid_reg: &P) -> Option +pub fn ray_marching

(p: &XYClip, dir: &NormedVector2, valid_reg: &P) -> Option> where - P: ProjDef + P: ProjDef, { // This is done so that we get further a little bit - let in_clip_space = |p: &XYClip| -> bool { + let in_clip_space = |p: &XYClip| -> bool { ((-1.0)..=1.0).contains(&p.x) && ((-1.0)..=1.0).contains(&p.y) }; @@ -49,13 +49,7 @@ where } } -use super::{ - basic::disk::Disk, - full::FullScreen, - hpx::Hpx, - par::Par, - cod::Cod -}; +use super::{basic::disk::Disk, cod::Cod, full::FullScreen, hpx::Hpx, par::Par}; // List of all the footprints // found in Aladin Lite diff --git a/src/core/src/math/projection/mod.rs b/src/core/src/math/projection/mod.rs index 64a4c0c1..975e06e5 100644 --- a/src/core/src/math/projection/mod.rs +++ b/src/core/src/math/projection/mod.rs @@ -23,9 +23,9 @@ use domain::{basic, full::FullScreen}; /* S <-> NDC space conversion methods */ pub fn screen_to_ndc_space( - pos_screen_space: &Vector2, + pos_screen_space: &XYScreen, camera: &CameraViewPort, -) -> Vector2 { +) -> XYNDC { // Screen space in pixels to homogeneous screen space (values between [-1, 1]) let window_size = camera.get_screen_size(); let window_size = Vector2::new(window_size.x as f64, window_size.y as f64); @@ -42,9 +42,9 @@ pub fn screen_to_ndc_space( } pub fn ndc_to_screen_space( - pos_normalized_device: &Vector2, + pos_normalized_device: &XYNDC, camera: &CameraViewPort, -) -> Vector2 { +) -> XYScreen { let window_size = camera.get_screen_size(); let dpi = camera.get_dpi() as f64; @@ -57,7 +57,7 @@ pub fn ndc_to_screen_space( } /* NDC <-> CLIP space conversion methods */ -pub fn clip_to_ndc_space(pos_clip_space: &Vector2, camera: &CameraViewPort) -> Vector2 { +pub fn clip_to_ndc_space(pos_clip_space: &XYClip, camera: &CameraViewPort) -> XYNDC { let ndc_to_clip = camera.get_ndc_to_clip(); let clip_zoom_factor = camera.get_clip_zoom_factor(); @@ -68,9 +68,9 @@ pub fn clip_to_ndc_space(pos_clip_space: &Vector2, camera: &CameraViewPort) } pub fn ndc_to_clip_space( - pos_normalized_device: &Vector2, + pos_normalized_device: &XYNDC, camera: &CameraViewPort, -) -> Vector2 { +) -> XYClip { let ndc_to_clip = camera.get_ndc_to_clip(); let clip_zoom_factor = camera.get_clip_zoom_factor(); @@ -82,17 +82,17 @@ pub fn ndc_to_clip_space( /* S <-> CLIP space conversion methods */ pub fn clip_to_screen_space( - pos_clip_space: &Vector2, + pos_clip_space: &XYClip, camera: &CameraViewPort, -) -> Vector2 { +) -> XYScreen { let pos_normalized_device = clip_to_ndc_space(pos_clip_space, camera); ndc_to_screen_space(&pos_normalized_device, camera) } pub fn screen_to_clip_space( - pos_screen_space: &Vector2, + pos_screen_space: &XYScreen, camera: &CameraViewPort, -) -> Vector2 { +) -> XYClip { let pos_normalized_device = screen_to_ndc_space(pos_screen_space, camera); ndc_to_clip_space(&pos_normalized_device, camera) } @@ -161,9 +161,9 @@ impl ProjectionType { /// * ``camera`` - The camera object pub fn screen_to_world_space( &self, - pos_screen_space: &Vector2, + pos_screen_space: &XYScreen, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { // Change the screen position according to the dpi //let dpi = camera.get_dpi(); let pos_screen_space = *pos_screen_space; @@ -171,13 +171,6 @@ impl ProjectionType { let pos_clip_space = ndc_to_clip_space(&pos_normalized_device, camera); self.clip_to_world_space(&pos_clip_space) - /*.map(|mut pos_world_space| { - if camera.get_longitude_reversed() { - pos_world_space.x = -pos_world_space.x; - } - - pos_world_space.normalize() - })*/ } /// Screen to model space deprojection @@ -190,27 +183,27 @@ impl ProjectionType { /// * ``camera`` - The camera object pub fn screen_to_model_space( &self, - pos_screen_space: &Vector2, + pos_screen_space: &XYScreen, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { self.screen_to_world_space(pos_screen_space, camera) .map(|world_pos| camera.get_w2m() * world_pos) } pub fn normalized_device_to_model_space( &self, - ndc_pos: &XYNDC, + ndc_pos: &XYNDC, camera: &CameraViewPort, - ) -> Option { + ) -> Option> { self.normalized_device_to_world_space(ndc_pos, camera) .map(|world_pos| camera.get_w2m() * world_pos) } pub fn model_to_screen_space( &self, - pos_model_space: &Vector4, + pos_model_space: &XYZWModel, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { let m2w = camera.get_m2w(); let pos_world_space = m2w * pos_model_space; self.world_to_screen_space(&pos_world_space, camera) @@ -218,23 +211,23 @@ impl ProjectionType { pub fn view_to_screen_space( &self, - pos_model_space: &Vector4, + pos_model_space: &XYZWModel, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { self.view_to_normalized_device_space(pos_model_space, camera) .map(|ndc_pos| crate::ndc_to_screen_space(&ndc_pos, camera)) } pub fn view_to_normalized_device_space( &self, - pos_view_space: &Vector4, + pos_model_space: &XYZWModel, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { let view_coosys = camera.get_coo_system(); let c = CooSystem::ICRS.to::(view_coosys); let m2w = camera.get_m2w(); - let pos_world_space = m2w * c * pos_view_space; + let pos_world_space = m2w * c * pos_model_space; self.world_to_normalized_device_space(&pos_world_space, camera) } @@ -253,9 +246,9 @@ impl ProjectionType { pub fn model_to_normalized_device_space( &self, - pos_model_space: &XYZWModel, + pos_model_space: &XYZWModel, camera: &CameraViewPort, - ) -> Option { + ) -> Option> { let m2w = camera.get_m2w(); let pos_world_space = m2w * pos_model_space; self.world_to_normalized_device_space(&pos_world_space, camera) @@ -263,9 +256,9 @@ impl ProjectionType { pub fn model_to_clip_space( &self, - pos_model_space: &XYZWModel, + pos_model_space: &XYZWModel, camera: &CameraViewPort, - ) -> Option { + ) -> Option> { let m2w = camera.get_m2w(); let pos_world_space = m2w * pos_model_space; self.world_to_clip_space(&pos_world_space) @@ -281,27 +274,27 @@ impl ProjectionType { /// * `y` - Y mouse position in homogenous screen space (between [-1, 1]) pub fn world_to_normalized_device_space( &self, - pos_world_space: &Vector4, + pos_world_space: &XYZWWorld, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { self.world_to_clip_space(pos_world_space) .map(|pos_clip_space| clip_to_ndc_space(&pos_clip_space, camera)) } pub fn normalized_device_to_world_space( &self, - ndc_pos: &XYNDC, + ndc_pos: &XYNDC, camera: &CameraViewPort, - ) -> Option { + ) -> Option> { let clip_pos = ndc_to_clip_space(ndc_pos, camera); self.clip_to_world_space(&clip_pos) } pub fn world_to_screen_space( &self, - pos_world_space: &Vector4, + pos_world_space: &XYZWWorld, camera: &CameraViewPort, - ) -> Option> { + ) -> Option> { self.world_to_normalized_device_space(pos_world_space, camera) .map(|pos_normalized_device| ndc_to_screen_space(&pos_normalized_device, camera)) } @@ -523,7 +516,7 @@ impl ProjectionType { impl Projection for ProjectionType { /// Deprojection - fn clip_to_world_space(&self, xy: &XYClip) -> Option { + fn clip_to_world_space(&self, xy: &XYClip) -> Option> { match self { // Zenithal projections /* TAN, Gnomonic projection */ @@ -579,7 +572,7 @@ impl Projection for ProjectionType { } // Projection - fn world_to_clip_space(&self, xyzw: &XYZWWorld) -> Option { + fn world_to_clip_space(&self, xyzw: &XYZWWorld) -> Option> { match self { // Zenithal projections /* TAN, Gnomonic projection */ @@ -635,6 +628,35 @@ impl Projection for ProjectionType { } } +use al_core::shader::UniformType; +use al_core::WebGlContext; +use web_sys::WebGlUniformLocation; +impl UniformType for ProjectionType { + fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, value: &Self) { + match value { + // Zenithal projections + /* TAN, Gnomonic projection */ + ProjectionType::Tan(_) => gl.uniform1i(location, 0), + /* STG, Stereographic projection */ + ProjectionType::Stg(_) => gl.uniform1i(location, 1), + /* SIN, Orthographic */ + ProjectionType::Sin(_) => gl.uniform1i(location, 2), + /* ZEA, Equal-area */ + ProjectionType::Zea(_) => gl.uniform1i(location, 3), + + // Pseudo-cylindrical projections + /* AIT, Aitoff */ + ProjectionType::Ait(_) => gl.uniform1i(location, 4), + // MOL, Mollweide */ + ProjectionType::Mol(_) => gl.uniform1i(location, 5), + + // Cylindrical projections + // MER, Mercator */ + ProjectionType::Mer(_) => gl.uniform1i(location, 6), + } + } +} + use cgmath::Vector4; use mapproj::CanonicalProjection; @@ -644,17 +666,18 @@ pub trait Projection { /// # Arguments /// /// * ``pos_clip_space`` - The position in the clipping space (orthonorlized space) - fn clip_to_world_space(&self, xy_clip: &XYClip) -> Option; + fn clip_to_world_space(&self, xy_clip: &XYClip) -> Option>; /// World to the clipping space deprojection /// /// # Arguments /// /// * ``pos_world_space`` - The position in the world space - fn world_to_clip_space(&self, pos_world_space: &XYZWWorld) -> Option; + fn world_to_clip_space(&self, pos_world_space: &XYZWWorld) -> Option>; } use mapproj::ProjXY; +use self::coo_space::XYScreen; use self::coo_space::XYNDC; impl<'a, P> Projection for &'a P @@ -666,7 +689,7 @@ where /// # Arguments /// /// * ``pos_clip_space`` - The position in the clipping space (orthonorlized space) - fn clip_to_world_space(&self, xy_clip: &XYClip) -> Option { + fn clip_to_world_space(&self, xy_clip: &XYClip) -> Option> { let proj_bounds = self.bounds(); // Scale the xy_clip space so that it maps the proj definition domain of mapproj let xy_mapproj = { @@ -699,7 +722,7 @@ where /// # Arguments /// /// * ``pos_world_space`` - The position in the world space - fn world_to_clip_space(&self, pos_world_space: &XYZWWorld) -> Option { + fn world_to_clip_space(&self, pos_world_space: &XYZWWorld) -> Option> { // Xmpp <-> Zal // -Ympp <-> Xal // Zmpp <-> Yal diff --git a/src/core/src/math/sph_geom/region.rs b/src/core/src/math/sph_geom/region.rs index 03ba94a5..523730f7 100644 --- a/src/core/src/math/sph_geom/region.rs +++ b/src/core/src/math/sph_geom/region.rs @@ -38,11 +38,11 @@ pub enum Intersection { // The segment does not intersect the region Empty, // The segment does intersect the region - Intersect { vertices: Box<[XYZWModel]> }, + Intersect { vertices: Box<[XYZWModel]> }, } impl Region { - pub fn from_vertices(vertices: &[XYZWModel], control_point: &XYZWModel) -> Self { + pub fn from_vertices(vertices: &[XYZWModel], control_point: &XYZWModel) -> Self { let (vertices, (lon, lat)): (Vec<_>, (Vec<_>, Vec<_>)) = vertices .iter() .map(|v| { diff --git a/src/core/src/renderable/coverage/moc.rs b/src/core/src/renderable/coverage/moc.rs index 5e636422..a52ff9e2 100644 --- a/src/core/src/renderable/coverage/moc.rs +++ b/src/core/src/renderable/coverage/moc.rs @@ -1,9 +1,9 @@ -use al_api::moc::MOC as Cfg; - use crate::camera::CameraViewPort; +use crate::coo_space::CooSpace; use crate::healpix::cell::CellVertices; use crate::healpix::coverage::HEALPixCoverage; use crate::math::projection::ProjectionType; +use al_api::moc::MOC as Cfg; use crate::renderable::coverage::Angle; @@ -312,6 +312,7 @@ impl MOCIntern { thickness, &color, &super::line::Style::None, + CooSpace::NDC, ); } RenderModeType::Edge { thickness, color } => { @@ -320,12 +321,14 @@ impl MOCIntern { thickness, &color, &super::line::Style::None, + CooSpace::LonLat, ); } RenderModeType::Filled { color } => { rasterizer.add_fill_paths( self.compute_edge_paths_iter(moc, view_moc, camera, proj), &color, + CooSpace::NDC, ); } } @@ -352,52 +355,63 @@ impl MOCIntern { false }; - self.vertices_in_view(view_moc, moc, camera) - .filter_map(move |cell_vertices| { - let mut ndc: [[f32; 2]; 5] = - [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]; - - let vertices = cell_vertices; - - for i in 0..4 { - let line_vertices = vertices[i]; - - //for k in 0..line_vertices.len() { - let (lon, lat) = line_vertices; - - let xyzw = crate::math::lonlat::radec_to_xyzw(Angle(lon), Angle(lat)); - let xyzw = - crate::coosys::apply_coo_system(CooSystem::ICRS, camera_coosys, &xyzw); - - if let Some(p) = proj.model_to_normalized_device_space(&xyzw, camera) { - if i > 0 && crossing_edges_testing { - let mag2 = crate::math::vector::dist2( - crate::math::projection::ndc_to_clip_space(&p, camera).as_ref(), - crate::math::projection::ndc_to_clip_space( - &Vector2::new(ndc[i - 1][0] as f64, ndc[i - 1][1] as f64), - camera, - ) - .as_ref(), - ); - //al_core::info!("mag", i, mag2); - if mag2 > 0.1 { - return None; - } + /*self.vertices_in_view(view_moc, moc, camera) + .filter_map(move |cell_vertices| { + let mut ndc: [[f32; 2]; 5] = + [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]]; + + let vertices = cell_vertices; + + for i in 0..4 { + let line_vertices = vertices[i]; + + //for k in 0..line_vertices.len() { + let (lon, lat) = line_vertices; + + let xyzw = crate::math::lonlat::radec_to_xyzw(Angle(lon), Angle(lat)); + let xyzw = + crate::coosys::apply_coo_system(CooSystem::ICRS, camera_coosys, &xyzw); + + if let Some(p) = proj.model_to_normalized_device_space(&xyzw, camera) { + if i > 0 && crossing_edges_testing { + let mag2 = crate::math::vector::dist2( + crate::math::projection::ndc_to_clip_space(&p, camera).as_ref(), + crate::math::projection::ndc_to_clip_space( + &Vector2::new(ndc[i - 1][0] as f64, ndc[i - 1][1] as f64), + camera, + ) + .as_ref(), + ); + //al_core::info!("mag", i, mag2); + if mag2 > 0.1 { + return None; } - - ndc[i] = [p.x as f32, p.y as f32]; - } else { - return None; } - //ndc[i] = [xyzw.x as f32, xyzw.y as f32]; - //ndc[i] = [lon as f32, lat as f32]; + ndc[i] = [p.x as f32, p.y as f32]; + } else { + return None; } - ndc[4] = ndc[0].clone(); + //ndc[i] = [xyzw.x as f32, xyzw.y as f32]; + //ndc[i] = [lon as f32, lat as f32]; + } - Some(PathVertices { vertices: ndc }) - }) + ndc[4] = ndc[0].clone(); + + Some(PathVertices { vertices: ndc }) + })*/ + self.vertices_in_view(view_moc, moc, camera).map(|v| { + let vertices = [ + [v[0].0 as f32, v[0].1 as f32], + [v[1].0 as f32, v[1].1 as f32], + [v[2].0 as f32, v[2].1 as f32], + [v[3].0 as f32, v[3].1 as f32], + [v[0].0 as f32, v[0].1 as f32], + ]; + + PathVertices { vertices } + }) } fn compute_perimeter_paths_iter<'a>( diff --git a/src/core/src/renderable/hips/mod.rs b/src/core/src/renderable/hips/mod.rs index e99605f0..d96a7610 100644 --- a/src/core/src/renderable/hips/mod.rs +++ b/src/core/src/renderable/hips/mod.rs @@ -2,6 +2,7 @@ pub mod raytracing; mod triangulation; pub mod uv; +use al_api::coo_system::CooSystem; use al_api::hips::ImageExt; use al_api::hips::ImageMetadata; use al_core::colormap::Colormap; @@ -42,7 +43,7 @@ use crate::survey::texture::Texture; use raytracing::RayTracer; use uv::{TileCorner, TileUVW}; -use cgmath::{Matrix}; +use cgmath::Matrix; use std::fmt::Debug; use wasm_bindgen::JsValue; @@ -286,28 +287,33 @@ pub fn get_raster_shader<'a>( config: &HiPSConfig, ) -> Result<&'a Shader, JsValue> { if config.get_format().is_colored() && cmap.label() == "native" { - crate::shader::get_shader(gl, shaders, "RasterizerVS", "RasterizerColorFS") + crate::shader::get_shader( + gl, + shaders, + "hips_rasterizer_raster.vert", + "hips_rasterizer_color.frag", + ) } else { if config.tex_storing_unsigned_int { crate::shader::get_shader( gl, shaders, - "RasterizerVS", - "RasterizerGrayscale2ColormapUnsignedFS", + "hips_rasterizer_raster.vert", + "hips_rasterizer_grayscale_to_colormap_u.frag", ) } else if config.tex_storing_integers { crate::shader::get_shader( gl, shaders, - "RasterizerVS", - "RasterizerGrayscale2ColormapIntegerFS", + "hips_rasterizer_raster.vert", + "hips_rasterizer_grayscale_to_colormap_i.frag", ) } else { crate::shader::get_shader( gl, shaders, - "RasterizerVS", - "RasterizerGrayscale2ColormapFS", + "hips_rasterizer_raster.vert", + "hips_rasterizer_grayscale_to_colormap.frag", ) } } @@ -321,24 +327,34 @@ pub fn get_raytracer_shader<'a>( ) -> Result<&'a Shader, JsValue> { //let colored_hips = config.is_colored(); if config.get_format().is_colored() && cmap.label() == "native" { - crate::shader::get_shader(gl, shaders, "RayTracerVS", "RayTracerColorFS") + crate::shader::get_shader( + gl, + shaders, + "hips_raytracer_raytracer.vert", + "hips_raytracer_color.frag", + ) } else { if config.tex_storing_unsigned_int { crate::shader::get_shader( gl, shaders, - "RayTracerVS", - "RayTracerGrayscale2ColormapUnsignedFS", + "hips_raytracer_raytracer.vert", + "hips_raytracer_grayscale_to_colormap_u.frag", ) } else if config.tex_storing_integers { crate::shader::get_shader( gl, shaders, - "RayTracerVS", - "RayTracerGrayscale2ColormapIntegerFS", + "hips_raytracer_raytracer.vert", + "hips_raytracer_grayscale_to_colormap_i.frag", ) } else { - crate::shader::get_shader(gl, shaders, "RayTracerVS", "RayTracerGrayscale2ColormapFS") + crate::shader::get_shader( + gl, + shaders, + "hips_raytracer_raytracer.vert", + "hips_raytracer_grayscale_to_colormap.frag", + ) } } } @@ -700,12 +716,12 @@ impl HiPS { let hips_frame = cfg.get_frame(); // Retrieve the model and inverse model matrix - let mut off_indices = 0; let depth = camera.get_texture_depth().min(cfg.get_max_depth_texture()); let view_cells: Vec<_> = camera.get_hpx_cells(depth, hips_frame).cloned().collect(); + for cell in &view_cells { // filter textures that are not in the moc let cell = if let Some(moc) = self.footprint_moc.as_ref() { @@ -812,11 +828,14 @@ impl HiPS { let n_vertices_per_segment = n_segments_by_side + 1; let mut pos = vec![]; - for (idx, lonlat) in - crate::healpix::utils::grid_lonlat::(cell, n_segments_by_side as u16) - .iter() - .enumerate() - { + + let grid_lonlat = + healpix::nested::grid(cell.depth(), cell.idx(), n_segments_by_side as u16); + let grid_lonlat_iter = grid_lonlat + .into_iter() + .map(|(lon, lat)| LonLatT::new(Angle(*lon), Angle(*lat))); + + for (idx, lonlat) in grid_lonlat_iter.enumerate() { let lon = lonlat.lon(); let lat = lonlat.lat(); @@ -1073,13 +1092,10 @@ impl HiPS { let shader = get_raster_shader(cmap, &self.gl, shaders, &config)?.bind(&self.gl); shader - .attach_uniforms_from(camera) .attach_uniforms_from(&self.textures) // send the cmap appart from the color config .attach_uniforms_with_params_from(cmap, colormaps) .attach_uniforms_from(color) - .attach_uniform("model", &w2v) - .attach_uniform("inv_model", &v2w) .attach_uniform("current_time", &utils::get_current_time()) .attach_uniform("opacity", opacity) .attach_uniforms_from(colormaps) diff --git a/src/core/src/renderable/image/mod.rs b/src/core/src/renderable/image/mod.rs index 8376da22..5cd4e9b5 100644 --- a/src/core/src/renderable/image/mod.rs +++ b/src/core/src/renderable/image/mod.rs @@ -572,19 +572,30 @@ impl Image { } = cfg; let shader = match self.channel { - ChannelType::R32F => crate::shader::get_shader(&self.gl, shaders, "FitsVS", "FitsFS")?, - #[cfg(feature = "webgl2")] - ChannelType::R32I => { - crate::shader::get_shader(&self.gl, shaders, "FitsVS", "FitsFSInteger")? + ChannelType::R32F => { + crate::shader::get_shader(&self.gl, shaders, "fits_base.vert", "fits_sampler.frag")? } #[cfg(feature = "webgl2")] - ChannelType::R16I => { - crate::shader::get_shader(&self.gl, shaders, "FitsVS", "FitsFSInteger")? - } + ChannelType::R32I => crate::shader::get_shader( + &self.gl, + shaders, + "fits_base.vert", + "fits_isampler.frag", + )?, #[cfg(feature = "webgl2")] - ChannelType::R8UI => { - crate::shader::get_shader(&self.gl, shaders, "FitsVS", "FitsFSUnsigned")? - } + ChannelType::R16I => crate::shader::get_shader( + &self.gl, + shaders, + "fits_base.vert", + "fits_isampler.frag", + )?, + #[cfg(feature = "webgl2")] + ChannelType::R8UI => crate::shader::get_shader( + &self.gl, + shaders, + "fits_base.vert", + "fits_usampler.frag", + )?, _ => return Err(JsValue::from_str("Image format type not supported")), }; diff --git a/src/core/src/renderable/line/great_circle_arc.rs b/src/core/src/renderable/line/great_circle_arc.rs index fb798d09..05b1675c 100644 --- a/src/core/src/renderable/line/great_circle_arc.rs +++ b/src/core/src/renderable/line/great_circle_arc.rs @@ -1,17 +1,12 @@ - - - -use cgmath::Vector3; -use crate::ProjectionType; use crate::CameraViewPort; +use crate::ProjectionType; +use cgmath::Vector3; -use cgmath::InnerSpace; use crate::math::angle::ToAngle; +use cgmath::InnerSpace; - -use crate::coo_space::XYNDC; use crate::coo_space::XYZModel; - +use crate::coo_space::XYNDC; use crate::LonLatT; const MAX_ITERATION: usize = 5; @@ -21,7 +16,14 @@ const MAX_ITERATION: usize = 5; // * Longitudes between [0; 2\pi[ // * (lon1 - lon2).abs() < PI so that is can only either cross the preimary meridian or opposite primary meridian // (the latest is handled because of the longitudes intervals) -pub fn project(lon1: f64, lat1: f64, lon2: f64, lat2: f64, camera: &CameraViewPort, projection: &ProjectionType) -> Vec { +pub fn project( + lon1: f64, + lat1: f64, + lon2: f64, + lat2: f64, + camera: &CameraViewPort, + projection: &ProjectionType, +) -> Vec> { let mut vertices = vec![]; let lonlat1 = LonLatT::new(lon1.to_angle(), lat1.to_angle()); @@ -36,18 +38,16 @@ pub fn project(lon1: f64, lat1: f64, lon2: f64, lat2: f64, camera: &CameraViewPo match (p1, p2) { (Some(_), Some(_)) => { project_line(&mut vertices, &v1, &v2, camera, projection, 0); - }, + } (None, Some(_)) => { let (v1, v2) = sub_valid_domain(v2, v1, projection, camera); project_line(&mut vertices, &v1, &v2, camera, projection, 0); - }, + } (Some(_), None) => { let (v1, v2) = sub_valid_domain(v1, v2, projection, camera); project_line(&mut vertices, &v1, &v2, camera, projection, 0); - }, - (None, None) => { - } + (None, None) => {} } vertices @@ -57,7 +57,12 @@ pub fn project(lon1: f64, lat1: f64, lon2: f64, lat2: f64, camera: &CameraViewPo // * angular distance between valid_lon and invalid_lon is < PI // * valid_lon and invalid_lon are well defined, i.e. they can be between [-PI; PI] or [0, 2PI] depending // whether they cross or not the zero meridian -fn sub_valid_domain(valid_v: XYZModel, invalid_v: XYZModel, projection: &ProjectionType, camera: &CameraViewPort) -> (XYZModel, XYZModel) { +fn sub_valid_domain( + valid_v: XYZModel, + invalid_v: XYZModel, + projection: &ProjectionType, + camera: &CameraViewPort, +) -> (XYZModel, XYZModel) { let d_alpha = camera.get_aperture().to_radians() * 0.02; let mut vv = valid_v; @@ -77,9 +82,9 @@ fn sub_valid_domain(valid_v: XYZModel, invalid_v: XYZModel, projection: &Project } fn project_line( - vertices: &mut Vec, - v1: &XYZModel, - v2: &XYZModel, + vertices: &mut Vec>, + v1: &XYZModel, + v2: &XYZModel, camera: &CameraViewPort, projection: &ProjectionType, iter: usize, @@ -91,25 +96,14 @@ fn project_line( // Project them. We are always facing the camera let vm = (v1 + v2).normalize(); let pm = projection.model_to_normalized_device_space(&vm.extend(1.0), camera); - + match (p1, pm, p2) { (Some(p1), Some(pm), Some(p2)) => { let d12 = crate::math::vector::angle3(v1, v2).to_radians(); // Subdivide when until it is > 30 degrees if d12 > 30.0_f64.to_radians() { - subdivide( - vertices, - v1, - v2, - &vm, - p1, - p2, - pm, - camera, - projection, - iter - ); + subdivide(vertices, v1, v2, &vm, p1, p2, pm, camera, projection, iter); } else { // enough to stop the recursion let ab = pm - p1; @@ -131,7 +125,7 @@ fn project_line( // not colinear but enough to stop vertices.push(p1); vertices.push(pm); - + vertices.push(pm); vertices.push(p2); } @@ -151,65 +145,39 @@ fn project_line( } } else { // Subdivide a->b and b->c - subdivide( - vertices, - v1, - v2, - &vm, - p1, - p2, - pm, - camera, - projection, - iter - ); + subdivide(vertices, v1, v2, &vm, p1, p2, pm, camera, projection, iter); } } } true - }, - _ => false + } + _ => false, } } else { false } } - fn subdivide( - vertices: &mut Vec, - v1: &XYZModel, - v2: &XYZModel, - vm: &XYZModel, - p1: XYNDC, - p2: XYNDC, - pm: XYNDC, + vertices: &mut Vec>, + v1: &XYZModel, + v2: &XYZModel, + vm: &XYZModel, + p1: XYNDC, + p2: XYNDC, + pm: XYNDC, camera: &CameraViewPort, projection: &ProjectionType, - iter: usize + iter: usize, ) { // Subdivide a->b and b->c - if !project_line( - vertices, - v1, - vm, - camera, - projection, - iter + 1 - ) { + if !project_line(vertices, v1, vm, camera, projection, iter + 1) { vertices.push(p1); vertices.push(pm); } - if !project_line( - vertices, - vm, - v2, - camera, - projection, - iter + 1 - ) { + if !project_line(vertices, vm, v2, camera, projection, iter + 1) { vertices.push(pm); vertices.push(p2); } diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index 53fc8d7d..ad85d0db 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -2,7 +2,10 @@ pub mod great_circle_arc; pub mod parallel_arc; +use crate::math::projection::ProjectionType; +use crate::shader::ShaderManager; use crate::Abort; +use al_api::coo_system::CooSystem; use al_core::shader::Shader; use al_core::VertexArrayObject; use al_core::WebGlContext; @@ -18,6 +21,7 @@ struct Meta { thickness: f32, off_indices: usize, num_indices: usize, + coo_space: CooSpace, } #[derive(Clone)] @@ -29,11 +33,8 @@ pub enum Style { pub struct RasterizedLineRenderer { gl: WebGlContext, - shader: Shader, vao: VertexArrayObject, - shader_line_instanced: Shader, - vao_idx: usize, vertices: Vec, @@ -52,13 +53,37 @@ use crate::camera::CameraViewPort; use lyon::tessellation::*; +use crate::coo_space::CooSpace; + +/*impl GPUVertexAttribute for XYZModel { + const Space: CooSpace = CooSpace::Model; + + fn as_ref(&self) -> &[S] { + &self[..] + } +} +impl GPUVertexAttribute for LonLatT { + const Space: CooSpace = CooSpace::LonLat; + + fn as_ref(&self) -> &[S] { + let addr = self as *const LonLatT as *const S; + unsafe { std::slice::from_raw_parts(addr, 2) } + } +}*/ +/* +impl GPUVertexAttribute for XYZModel { + const Space: CooSpace = CooSpace::Model; +} +impl GPUVertexAttribute for LonLatT { + const Space: CooSpace = CooSpace::LonLat; +}*/ + #[repr(C)] -pub struct PathVertices +pub struct PathVertices where - T: AsRef<[[f32; 2]]>, + V: AsRef<[[f32; 2]]>, { - pub vertices: T, - //pub closed: bool, + pub vertices: V, } impl RasterizedLineRenderer { @@ -67,43 +92,6 @@ impl RasterizedLineRenderer { let vertices = vec![]; let indices = vec![]; // Create the VAO for the screen - let shader = Shader::new( - &gl, - include_str!("../../../../glsl/webgl2/line/line_vertex.glsl"), - include_str!("../../../../glsl/webgl2/line/line_frag.glsl"), - )?; - let shader_line_instanced = Shader::new( - &gl, - r#"#version 300 es - precision lowp float; - layout (location = 0) in vec2 p_a; - layout (location = 1) in vec2 p_b; - layout (location = 2) in vec2 vertex; - - out vec2 out_uv; - out vec3 out_p; - - uniform float u_width; - - void main() { - vec2 x_b = p_b - p_a; - vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); - - vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y; - gl_Position = vec4(p, 0.f, 1.f); - }"#, - r#"#version 300 es - precision lowp float; - out vec4 color; - - uniform vec4 u_color; - - void main() { - // Multiply vertex color with texture color (in linear space). - // Linear color is written and blended in Framebuffer and converted to sRGB later - color = u_color; - }"#, - )?; let mut vao = VertexArrayObject::new(&gl); vao.bind_for_update() @@ -129,8 +117,6 @@ impl RasterizedLineRenderer { let instanced_line_vaos = vec![]; Ok(Self { gl, - shader, - shader_line_instanced, vao_idx: 0, instanced_line_vaos, meta_instanced, @@ -141,12 +127,13 @@ impl RasterizedLineRenderer { }) } - pub fn add_fill_paths( + pub fn add_fill_paths( &mut self, - paths: impl Iterator>, + paths: impl Iterator>, color: &ColorRGBA, + coo_space: CooSpace, ) where - T: AsRef<[[f32; 2]]>, + V: AsRef<[[f32; 2]]>, { let mut num_indices = 0; let off_indices = self.indices.len(); @@ -162,7 +149,7 @@ impl RasterizedLineRenderer { vertices, /*, closed */ } = path; - let line: &[[f32; 2]] = vertices.as_ref(); + let line = vertices.as_ref(); if !line.is_empty() { let v = &line[0]; @@ -212,6 +199,7 @@ impl RasterizedLineRenderer { num_indices, thickness: 1.0, color: color.clone(), + coo_space, }); } @@ -249,14 +237,15 @@ impl RasterizedLineRenderer { self.instanced_line_vaos.push(vao); } - pub fn add_stroke_paths( + pub fn add_stroke_paths( &mut self, - paths: impl Iterator>, + paths: impl Iterator>, thickness: f32, color: &ColorRGBA, _style: &Style, + coo_space: CooSpace, ) where - T: AsRef<[[f32; 2]]>, + V: AsRef<[[f32; 2]]>, { //let num_vertices = (self.vertices.len() / 2) as u32; @@ -381,10 +370,16 @@ impl RasterizedLineRenderer { thickness, num_indices: num_instances, color: color.clone(), + coo_space, }); } - pub fn draw(&mut self, _camera: &CameraViewPort) -> Result<(), JsValue> { + pub fn draw( + &mut self, + shaders: &mut ShaderManager, + camera: &CameraViewPort, + proj: &ProjectionType, + ) -> Result<(), JsValue> { self.gl.enable(WebGl2RenderingContext::BLEND); self.gl.blend_func_separate( WebGl2RenderingContext::SRC_ALPHA, @@ -394,35 +389,70 @@ impl RasterizedLineRenderer { ); //self.gl.disable(WebGl2RenderingContext::CULL_FACE); - - let shader = self.shader.bind(&self.gl); - for meta in self.meta.iter() { - shader - .attach_uniform("u_color", &meta.color) // Strengh of the kernel - .bind_vertex_array_object_ref(&self.vao) - .draw_elements_with_i32( - WebGl2RenderingContext::TRIANGLES, - Some(meta.num_indices as i32), - WebGl2RenderingContext::UNSIGNED_INT, - ((meta.off_indices as usize) * std::mem::size_of::()) as i32, - ); + { + let shader = + crate::shader::get_shader(&self.gl, shaders, "line_base.vert", "line_base.frag")? + .bind(&self.gl); + for meta in self.meta.iter() { + shader + .attach_uniform("u_color", &meta.color) // Strengh of the kernel + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_with_i32( + WebGl2RenderingContext::TRIANGLES, + Some(meta.num_indices as i32), + WebGl2RenderingContext::UNSIGNED_INT, + ((meta.off_indices as usize) * std::mem::size_of::()) as i32, + ); + } } - //self.gl.enable(WebGl2RenderingContext::CULL_FACE); - // draw the lines - let shader_bound = self.shader_line_instanced.bind(&self.gl); + // draw the instanced lines for (idx, meta) in self.meta_instanced.iter().enumerate() { - let vao_bound = shader_bound - .attach_uniform("u_color", &meta.color) - .attach_uniform("u_width", &meta.thickness) - .bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]); - - vao_bound.draw_elements_instanced_with_i32( - WebGl2RenderingContext::TRIANGLES, - 0, - meta.num_indices as i32, - ); + match meta.coo_space { + CooSpace::NDC => { + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_ndc.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniform("u_color", &meta.color) + .attach_uniform("u_width", &meta.thickness) + .bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + meta.num_indices as i32, + ); + } + CooSpace::LonLat => { + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_lonlat.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &meta.color) + .attach_uniform("u_width", &meta.thickness) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + meta.num_indices as i32, + ); + } + _ => (), + } } self.gl.disable(WebGl2RenderingContext::BLEND); diff --git a/src/core/src/renderable/mod.rs b/src/core/src/renderable/mod.rs index 6273c1c8..df1b2e64 100644 --- a/src/core/src/renderable/mod.rs +++ b/src/core/src/renderable/mod.rs @@ -79,16 +79,19 @@ const DEFAULT_BACKGROUND_COLOR: ColorRGB = ColorRGB { b: 0.05, }; -fn get_backgroundcolor_shader<'a>(gl: &WebGlContext, shaders: &'a mut ShaderManager) -> &'a Shader { +fn get_backgroundcolor_shader<'a>( + gl: &WebGlContext, + shaders: &'a mut ShaderManager, +) -> Result<&'a Shader, JsValue> { shaders .get( gl, - &ShaderId( - Cow::Borrowed("RayTracerFontVS"), - Cow::Borrowed("RayTracerFontFS"), + ShaderId( + "hips_raytracer_backcolor.vert", + "hips_raytracer_backcolor.frag", ), ) - .unwrap_abort() + .map_err(|e| e.into()) } pub struct ImageCfg { @@ -258,7 +261,7 @@ impl Layers { &self.screen_vao }; - get_backgroundcolor_shader(&self.gl, shaders) + get_backgroundcolor_shader(&self.gl, shaders)? .bind(&self.gl) .attach_uniforms_from(camera) .attach_uniform("color", &background_color) diff --git a/src/core/src/shader.rs b/src/core/src/shader.rs index 79747189..aead1993 100644 --- a/src/core/src/shader.rs +++ b/src/core/src/shader.rs @@ -1,17 +1,16 @@ +use al_core::log::console_log; use al_core::shader::Shader; use al_core::WebGlContext; -pub type VertId = Cow<'static, str>; -pub type FragId = Cow<'static, str>; -type FileId = Cow<'static, str>; +pub type VertId = &'static str; +pub type FragId = &'static str; #[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct ShaderId(pub VertId, pub FragId); pub struct ShaderManager { // Compiled shaders stored in an HashMap shaders: HashMap, - // Shaders sources coming from the javascript - src: HashMap, + src: HashMap<&'static str, &'static str>, } #[derive(Debug)] @@ -20,6 +19,7 @@ pub enum Error { ShaderNotFound { message: &'static str }, ShaderCompilingLinking { message: JsValue }, FileNotFound { message: &'static str }, + Io { message: String }, } use wasm_bindgen::JsValue; @@ -35,7 +35,8 @@ impl From for JsValue { Error::FileNotFound { message } => { JsValue::from_str(&format!("Shader not found: {:?}", message)) } - Error::ShaderCompilingLinking { message } => message + Error::ShaderCompilingLinking { message } => message, + Error::Io { message } => message.into(), } } } @@ -49,15 +50,41 @@ pub struct FileSrc { use std::collections::hash_map::Entry; use std::collections::HashMap; +use std::fs::File; +use std::io::Read; impl ShaderManager { - pub fn new(_gl: &WebGlContext, files: Vec) -> Result { - let src = files - .into_iter() - .map(|file| { - let FileSrc { id, content } = file; - (Cow::Owned(id), content) - }) - .collect::>(); + pub fn new() -> Result { + let src = crate::shaders::get_all(); + // Loop over the entries in the directory + /*let _src = std::fs::read_dir("./shaders") + .map_err(|e| Error::Io { + message: e.to_string(), + })? + .into_iter() + .filter_map(|entry| { + let entry = entry.ok()?; + let path = entry.path(); + + console_log(&format!("aaa")); + + if path.is_file() { + let file_name = path.to_str()?; + + console_log(&format!("{}", file_name)); + + // read the file into a bufreader + let file = File::open(file_name).ok()?; + let mut reader = std::io::BufReader::new(file); + let mut content = String::new(); + + reader.read_to_string(&mut content).ok()?; + + Some((Cow::Owned(file_name.to_owned()), content)) + } else { + None + } + }) + .collect::>();*/ Ok(ShaderManager { shaders: HashMap::new(), @@ -65,21 +92,23 @@ impl ShaderManager { }) } - pub fn get(&mut self, gl: &WebGlContext, id: &ShaderId) -> Result<&Shader, Error> { + pub fn get(&mut self, gl: &WebGlContext, id: ShaderId) -> Result<&Shader, Error> { let shader = match self.shaders.entry(id.clone()) { Entry::Occupied(o) => o.into_mut(), Entry::Vacant(v) => { let ShaderId(vert_id, frag_id) = id; - let vert_src = self.src.get(vert_id).ok_or(Error::FileNotFound { - message: "Vert not found", - })?; - let frag_src = self.src.get(frag_id).ok_or(Error::FileNotFound { - message: "Frag not found", - })?; - - let shader = Shader::new(gl, vert_src, frag_src).map_err(|err| Error::ShaderCompilingLinking { - message: err, - })?; + + let &vert_src = self + .src + .get(vert_id) + .ok_or(Error::FileNotFound { message: vert_id })?; + let &frag_src = self + .src + .get(frag_id) + .ok_or(Error::FileNotFound { message: frag_id })?; + + let shader = Shader::new(gl, vert_src, frag_src) + .map_err(|err| Error::ShaderCompilingLinking { message: err })?; v.insert(shader) } }; @@ -88,59 +117,14 @@ impl ShaderManager { } } use std::borrow::Cow; -/*use paste::paste; -macro_rules! define_shader_getter { - ($renderer_type:ident, $shader_type:ident, $vert_key:tt, $frag_key:tt) => { - paste! { - pub fn [< get_ $renderer_type _shader_ $shader_type >]<'a>( - gl: &WebGlContext, - shaders: &'a mut ShaderManager - ) -> &'a Shader { - shaders.get( - gl, - &ShaderId( - Cow::Borrowed($vert_key), - Cow::Borrowed($frag_key), - ), - ) - .unwrap_abort() - } - } - } -} -/* Raytracer shaders */ -define_shader_getter!(raytracer, color, "RayTracerVS", "RayTracerColorFS"); -define_shader_getter!(raytracer, gray2colormap, "RayTracerVS", "RayTracerGrayscale2ColormapFS"); -define_shader_getter!(raytracer, gray2color, "RayTracerVS", "RayTracerGrayscale2ColorFS"); -define_shader_getter!(raytracer, gray2colormap_integer, "RayTracerVS", "RayTracerGrayscale2ColormapIntegerFS"); -define_shader_getter!(raytracer, gray2color_integer, "RayTracerVS", "RayTracerGrayscale2ColorIntegerFS"); -define_shader_getter!(raytracer, gray2colormap_unsigned, "RayTracerVS", "RayTracerGrayscale2ColormapUnsignedFS"); -define_shader_getter!(raytracer, gray2color_unsigned, "RayTracerVS", "RayTracerGrayscale2ColorUnsignedFS"); - -/* Rasterizer shaders */ -define_shader_getter!(raster, color, "RasterizerVS", "RasterizerColorFS"); -define_shader_getter!(raster, gray2colormap, "RasterizerVS", "RasterizerGrayscale2ColormapFS"); -define_shader_getter!(raster, gray2color, "RasterizerVS", "RasterizerGrayscale2ColorFS"); -define_shader_getter!(raster, gray2colormap_integer, "RasterizerVS", "RasterizerGrayscale2ColormapIntegerFS"); -define_shader_getter!(raster, gray2color_integer, "RasterizerVS", "RasterizerGrayscale2ColorIntegerFS"); -define_shader_getter!(raster, gray2colormap_unsigned, "RasterizerVS", "RasterizerGrayscale2ColormapUnsignedFS"); -define_shader_getter!(raster, gray2color_unsigned, "RasterizerVS", "RasterizerGrayscale2ColorUnsignedFS"); - -/* Pass shaders */ -define_shader_getter!(pass, post, "PostVS", "PostFS"); - -/* Catalog shaders */ -define_shader_getter!(catalog, ait, "CatalogAitoffVS", "CatalogFS"); -define_shader_getter!(catalog, mol, "CatalogMollVS", "CatalogFS"); -define_shader_getter!(catalog, arc, "CatalogArcVS", "CatalogFS"); -define_shader_getter!(catalog, hpx, "CatalogHEALPixVS", "CatalogFS"); -define_shader_getter!(catalog, mer, "CatalogMercatVS", "CatalogFS"); -define_shader_getter!(catalog, ort, "CatalogOrthoVS", "CatalogOrthoFS"); -define_shader_getter!(catalog, tan, "CatalogTanVS", "CatalogFS");*/ -pub(crate) fn get_shader<'a>(gl: &WebGlContext, shaders: &'a mut ShaderManager, vert: &'static str, frag: &'static str) -> Result<&'a Shader, JsValue> { - shaders.get( - gl, - &ShaderId(Cow::Borrowed(vert), Cow::Borrowed(frag)), - ).map_err(|err| err.into()) -} \ No newline at end of file +pub(crate) fn get_shader<'a>( + gl: &WebGlContext, + shaders: &'a mut ShaderManager, + vert: &'static str, + frag: &'static str, +) -> Result<&'a Shader, JsValue> { + shaders + .get(gl, ShaderId(vert, frag)) + .map_err(|err| err.into()) +} diff --git a/src/glsl/webgl1/catalogs/aitoff.vert b/src/glsl/webgl1/catalogs/aitoff.vert deleted file mode 100644 index 98bca1d8..00000000 --- a/src/glsl/webgl1/catalogs/aitoff.vert +++ /dev/null @@ -1,31 +0,0 @@ -precision lowp float; - -attribute vec2 offset; -attribute vec2 uv; -attribute vec3 center; - -uniform float current_time; -uniform mat4 model; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -varying vec2 out_uv; -varying vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_aitoff(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/arc.vert b/src/glsl/webgl1/catalogs/arc.vert deleted file mode 100644 index c0078754..00000000 --- a/src/glsl/webgl1/catalogs/arc.vert +++ /dev/null @@ -1,29 +0,0 @@ -precision lowp float; -attribute vec2 offset; -attribute vec2 uv; -attribute vec3 center; - -uniform float current_time; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -varying vec2 out_uv; -varying vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_arc(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/catalog.frag b/src/glsl/webgl1/catalogs/catalog.frag deleted file mode 100644 index 14d1ee8f..00000000 --- a/src/glsl/webgl1/catalogs/catalog.frag +++ /dev/null @@ -1,14 +0,0 @@ -precision lowp float; - -varying vec2 out_uv; -varying vec3 out_p; - -uniform sampler2D kernel_texture; -uniform float fov; -uniform float strength; -void main() { - vec4 color = texture2D(kernel_texture, out_uv) / max(log2(fov*100.0), 1.0); - color.r *= strength; - - gl_FragColor = color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/mercator.vert b/src/glsl/webgl1/catalogs/mercator.vert deleted file mode 100644 index 2b4b7e60..00000000 --- a/src/glsl/webgl1/catalogs/mercator.vert +++ /dev/null @@ -1,30 +0,0 @@ -precision lowp float; - -attribute vec2 offset; -attribute in vec2 uv; -attribute in vec3 center; - -uniform float current_time; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -varying vec2 out_uv; -varying vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_mercator(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/mollweide.vert b/src/glsl/webgl1/catalogs/mollweide.vert deleted file mode 100644 index af0ce054..00000000 --- a/src/glsl/webgl1/catalogs/mollweide.vert +++ /dev/null @@ -1,29 +0,0 @@ -precision lowp float; -attribute vec2 offset; -attribute vec2 uv; -attribute vec3 center; - -uniform float current_time; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -out vec2 out_uv; -out vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_mollweide(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/ortho.frag b/src/glsl/webgl1/catalogs/ortho.frag deleted file mode 100644 index 3f47647c..00000000 --- a/src/glsl/webgl1/catalogs/ortho.frag +++ /dev/null @@ -1,18 +0,0 @@ -precision lowp float; - -varying vec2 out_uv; -varying vec3 out_p; - -uniform sampler2D kernel_texture; -uniform float fov; -uniform float strength; -void main() { - if (out_p.z < 0.0) { - discard; - } - - vec4 color = texture2D(kernel_texture, out_uv).rgba / max(log2(fov*100.0), 1.0); - color.r *= strength; - - gl_FragColor = color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/ortho.vert b/src/glsl/webgl1/catalogs/ortho.vert deleted file mode 100644 index 0e198e8f..00000000 --- a/src/glsl/webgl1/catalogs/ortho.vert +++ /dev/null @@ -1,29 +0,0 @@ -precision lowp float; -attribute vec3 center; -attribute vec2 offset; -attribute vec2 uv; - -uniform float current_time; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -varying vec2 out_uv; -varying vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_orthographic(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/catalogs/tan.vert b/src/glsl/webgl1/catalogs/tan.vert deleted file mode 100644 index bb569f5c..00000000 --- a/src/glsl/webgl1/catalogs/tan.vert +++ /dev/null @@ -1,31 +0,0 @@ -precision lowp float; - -attribute vec2 offset; -attribute vec2 uv; -attribute vec3 center; -attribute vec2 center_lonlat; - -uniform float current_time; -uniform mat4 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -varying vec2 out_uv; -varying vec3 out_p; - -@import ../hips/projection; - -void main() { - vec3 p = vec3(inv_model * vec4(center, 1.0)); - //p = check_inversed_longitude(p); - - vec2 center_pos_clip_space = world2clip_gnomonic(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.0, 1.0); - - out_uv = uv; - out_p = p; -} \ No newline at end of file diff --git a/src/glsl/webgl1/colormaps/colormap.frag b/src/glsl/webgl1/colormaps/colormap.frag deleted file mode 100644 index df030898..00000000 --- a/src/glsl/webgl1/colormaps/colormap.frag +++ /dev/null @@ -1,20 +0,0 @@ -precision lowp float; -precision lowp sampler2D; - -varying vec2 out_uv; - -uniform sampler2D texture_fbo; -uniform float alpha; - -@import ./colormap; - -void main() { - float opacity = texture2D(texture_fbo, out_uv).r; - - float o = smoothstep(0.0, 0.1, opacity); - - vec4 color = colormap_f(opacity); - color.a = o * alpha; - - gl_FragColor = color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/colormaps/colormap.glsl b/src/glsl/webgl1/colormaps/colormap.glsl deleted file mode 100644 index c7f02418..00000000 --- a/src/glsl/webgl1/colormaps/colormap.glsl +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; -// can be either 0 or 1 -uniform float reversed; - -vec4 colormap_f(float x) { - x = mix(x, 1.0 - x, reversed); - float id = (colormap_id + 0.5) / num_colormaps; - - return texture2D(colormaps, vec2(x, id)); -} diff --git a/src/glsl/webgl1/colormaps/colormap.vert b/src/glsl/webgl1/colormaps/colormap.vert deleted file mode 100644 index 2577ba2b..00000000 --- a/src/glsl/webgl1/colormaps/colormap.vert +++ /dev/null @@ -1,12 +0,0 @@ -precision lowp float; -precision lowp sampler2D; - -attribute vec2 position; -attribute vec2 uv; - -varying vec2 out_uv; - -void main() { - gl_Position = vec4(position, 0.0, 1.0); - out_uv = uv; -} \ No newline at end of file diff --git a/src/glsl/webgl1/grid/grid_cpu.frag b/src/glsl/webgl1/grid/grid_cpu.frag deleted file mode 100644 index 4ccd37a9..00000000 --- a/src/glsl/webgl1/grid/grid_cpu.frag +++ /dev/null @@ -1,7 +0,0 @@ -precision lowp float; - -uniform vec4 color; - -void main() { - gl_FragColor = color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/grid/grid_cpu.vert b/src/glsl/webgl1/grid/grid_cpu.vert deleted file mode 100644 index 24307676..00000000 --- a/src/glsl/webgl1/grid/grid_cpu.vert +++ /dev/null @@ -1,7 +0,0 @@ -precision lowp float; - -attribute vec2 ndc_pos; - -void main() { - gl_Position = vec4(ndc_pos, 0.0, 1.0); -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/color.glsl b/src/glsl/webgl1/hips/color.glsl deleted file mode 100644 index c9079c5c..00000000 --- a/src/glsl/webgl1/hips/color.glsl +++ /dev/null @@ -1,82 +0,0 @@ -//const int MAX_NUM_TEX = 3; -uniform sampler2D tex1; -uniform sampler2D tex2; -uniform sampler2D tex3; - -uniform int num_tex; - -uniform float scale; -uniform float offset; -uniform float blank; - -uniform float min_value; -uniform float max_value; -uniform int H; - -uniform float size_tile_uv; - -uniform int tex_storing_fits; - -@import ../colormaps/colormap; -@import ./transfer_funcs; - -vec4 get_pixels(vec3 uv) { - int idx_texture = int(uv.z); - if (idx_texture == 0) { - return texture2D(tex1, uv.xy); - } else if (idx_texture == 1) { - return texture2D(tex2, uv.xy); - } else if (idx_texture == 2) { - return texture2D(tex3, uv.xy); - } else { - return vec4(0.0, 1.0, 1.0, 1.0); - } -} - -vec3 reverse_uv(vec3 uv) { - uv.y = size_tile_uv + 2.0*size_tile_uv*floor(uv.y / size_tile_uv) - uv.y; - - return uv; -} - -vec4 get_color_from_texture(vec3 UV) { - return get_pixels(UV); -} - -vec4 get_colormap_from_grayscale_texture(vec3 UV) { - vec3 uv = UV; - // FITS data pixels are reversed along the y axis - if (tex_storing_fits == 1) { - uv = reverse_uv(uv); - } - - float x = get_pixels(uv).r; - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - return mix(colormap_f(alpha), vec4(0.0), float(alpha == 0.0)); - //} -} - -uniform vec4 C; -uniform float K; -vec4 get_color_from_grayscale_texture(vec3 UV) { - vec3 uv = UV; - // FITS data pixels are reversed along the y axis - if (tex_storing_fits == 1) { - uv = reverse_uv(uv); - } - - float x = get_pixels(uv).r; - //if (x == blank) { - // return blank_color; - //} else { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - return mix(vec4(C.rgb * K * alpha, C.a), vec4(0.0), float(alpha == 0.0)); - //} -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/projection.glsl b/src/glsl/webgl1/hips/projection.glsl deleted file mode 100644 index 74591d84..00000000 --- a/src/glsl/webgl1/hips/projection.glsl +++ /dev/null @@ -1,158 +0,0 @@ -const float PI = 3.1415926535897932384626433832795; - -//uniform int inversed_longitude; - -const mat4 GAL2J2000 = mat4( - -0.4448296299195045, - 0.7469822444763707, - 0.4941094279435681, - 0.0, - - -0.1980763734646737, - 0.4559837762325372, - -0.8676661489811610, - 0.0, - - -0.873437090247923, - -0.4838350155267381, - -0.0548755604024359, - 0.0, - - 0.0, - 0.0, - 0.0, - 1.0 -); - -const mat4 J20002GAL = mat4( - -0.4448296299195045, - -0.1980763734646737, - -0.873437090247923, - 0.0, - - 0.7469822444763707, - 0.4559837762325372, - -0.4838350155267381, - 0.0, - - 0.4941094279435681, - -0.8676661489811610, - -0.0548755604024359, - 0.0, - - 0.0, - 0.0, - 0.0, - 1.0 -); - -vec2 world2clip_orthographic(vec3 p) { - return vec2(p.x, p.y); -} - -vec2 world2clip_aitoff(vec3 p) { - float delta = asin(p.y); - float theta = atan(p.x, p.z); - - float theta_by_two = theta * 0.5; - - float alpha = acos(cos(delta)*cos(theta_by_two)); - float inv_sinc_alpha = 1.0; - if (alpha > 1e-3) { - inv_sinc_alpha = alpha / sin(alpha); - } - - // The minus is an astronomical convention. - // longitudes are increasing from right to left - float x = 2.0 * inv_sinc_alpha * cos(delta) * sin(theta_by_two); - float y = inv_sinc_alpha * sin(delta); - - return vec2(x / PI, y / PI); -} - -const int max_iter = 10; -vec2 world2clip_mollweide(vec3 p) { - // X in [-1, 1] - // Y in [-1/2; 1/2] and scaled by the screen width/height ratio - float delta = asin(p.y); - float theta = atan(p.x, p.z); - - float cst = PI * sin(delta); - - float phi = delta; - float f = phi + sin(phi) - cst; - - int k = 0; - for (int k = 0; k < max_iter; k++) { - phi = phi - f / (1.0 + cos(phi)); - f = phi + sin(phi) - cst; - - if (abs(f) <= 1e-6) { - break; - } - } - - phi = phi * 0.5; - - // The minus is an astronomical convention. - // longitudes are increasing from right to left - float x = (theta / PI) * cos(phi); - float y = 0.5 * sin(phi); - - return vec2(x, y); -} - -float asinh(float x) { - return log(x + sqrt(x*x + 1.0)); -} -vec2 world2clip_mercator(vec3 p) { - // X in [-1, 1] - // Y in [-1/2; 1/2] and scaled by the screen width/height ratio - - float delta = asin(p.y); - float theta = atan(p.x, p.z); - - float x = theta / PI; - float y = asinh(tan(delta / PI)); - - return vec2(x, y); -} - -float arc_sinc(float x) { - if (x > 1e-4) { - return asin(x) / x; - } else { - // If a is mall, use Taylor expension of asin(a) / a - // a = 1e-4 => a^4 = 1.e-16 - float x2 = x*x; - return 1.0 + x2 * (1.0 + x2 * 9.0 / 20.0) / 6.0; - } -} - -vec2 world2clip_arc(vec3 p) { - if (p.z > -1.0) { - // Distance in the Euclidean plane (xy) - // Angular distance is acos(x), but for small separation, asin(r) - // is more accurate. - float r = length(p.xy); - if (p.z > 0.0) { // Angular distance < PI/2, angular distance = asin(r) - r = arc_sinc(r); - } else { // Angular distance > PI/2, angular distance = acos(x) - r = acos(p.z) / r; - } - float x = p.x * r; - float y = p.y * r; - - return vec2(x / PI, y / PI); - } else { - return vec2(1.0, 0.0); - } -} - -vec2 world2clip_gnomonic(vec3 p) { - if (p.z <= 1e-2) { // Back hemisphere (x < 0) + diverges near x=0 - return vec2(1.0, 0.0); - } else { - return vec2((p.x/p.z) / PI , (p.y/p.z) / PI); - } -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/rasterizer/color.frag b/src/glsl/webgl1/hips/rasterizer/color.frag deleted file mode 100644 index 8bf63a34..00000000 --- a/src/glsl/webgl1/hips/rasterizer/color.frag +++ /dev/null @@ -1,23 +0,0 @@ -precision mediump float; -precision mediump sampler2D; -precision mediump int; - -varying vec3 frag_uv_start; -varying vec3 frag_uv_end; -varying float frag_blending_factor; -varying float m_start; -varying float m_end; - -uniform float opacity; - -@import ../color; - -void main() { - vec4 color_start = get_color_from_texture(frag_uv_start); - vec4 color_end = get_color_from_texture(frag_uv_end); - - vec4 out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = opacity * out_frag_color.a; - - gl_FragColor = out_frag_color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/rasterizer/grayscale_to_colormap.frag b/src/glsl/webgl1/hips/rasterizer/grayscale_to_colormap.frag deleted file mode 100644 index 6197ab68..00000000 --- a/src/glsl/webgl1/hips/rasterizer/grayscale_to_colormap.frag +++ /dev/null @@ -1,29 +0,0 @@ -precision mediump float; -precision mediump sampler2D; -precision mediump int; - -varying vec3 frag_uv_start; -varying vec3 frag_uv_end; -varying float frag_blending_factor; -varying float m_start; -varying float m_end; - -@import ../color; - -uniform float opacity; - -vec4 get_color(vec3 uv, float empty) { - vec4 c = get_colormap_from_grayscale_texture(uv); - vec4 color = mix(c, vec4(0.0), empty); - return color; -} - -void main() { - vec4 color_start = get_color(frag_uv_start, m_start); - vec4 color_end = get_color(frag_uv_end, m_end); - - vec4 out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = out_frag_color.a * opacity; - - gl_FragColor = out_frag_color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/rasterizer/raster.vert b/src/glsl/webgl1/hips/rasterizer/raster.vert deleted file mode 100644 index 872edae8..00000000 --- a/src/glsl/webgl1/hips/rasterizer/raster.vert +++ /dev/null @@ -1,41 +0,0 @@ -precision mediump float; -precision mediump int; - -attribute vec3 position; -attribute vec3 uv_start; -attribute vec3 uv_end; -attribute float time_tile_received; -attribute float m0; -attribute float m1; - -varying vec3 frag_uv_start; -varying vec3 frag_uv_end; -varying float frag_blending_factor; -varying float m_start; -varying float m_end; - -uniform float czf; -uniform mat4 inv_model; -uniform vec2 ndc_to_clip; - -// current time in ms -uniform float current_time; - -@import ../projection; - -void main() { - - vec3 world_pos = vec3(inv_model * vec4(position, 1.0)); - //world_pos = check_inversed_longitude(world_pos); - - vec2 ndc_pos = world2clip_aitoff(world_pos) / (ndc_to_clip * czf); - - gl_Position = vec4(ndc_pos, 0.0, 1.0); - - frag_uv_start = uv_start; - frag_uv_end = uv_end; - - frag_blending_factor = min((current_time - time_tile_received) / 200.0, 1.0); - m_start = m0; - m_end = m1; -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/raytracer/color.frag b/src/glsl/webgl1/hips/raytracer/color.frag deleted file mode 100644 index 5db9b29d..00000000 --- a/src/glsl/webgl1/hips/raytracer/color.frag +++ /dev/null @@ -1,106 +0,0 @@ -precision highp float; -precision highp sampler2D; -precision highp int; - -varying vec3 out_vert_pos; -varying vec2 out_clip_pos; - -struct Tile { - int uniq; // Healpix cell - int texture_idx; // Index in the texture buffer - float start_time; // Absolute time that the load has been done in ms - float empty; -}; - -uniform Tile textures_tiles[192]; -uniform int num_tiles; - -uniform float current_time; // current time in ms - -@import ../color; -@import ./healpix; - -uniform float opacity; - -Tile get_tile(int idx) { - for(int i = 0; i < 12; i++) { - if( i == idx ) { - return textures_tiles[i]; - } - } -} - -Tile binary_search_tile(int uniq) { - int l = 0; - int r = 11; - for (int v = 0; v <= 5; v++) { - int mid = (l + r) / 2; - - Tile tile = get_tile(mid); - if(tile.uniq == uniq) { - return tile; - } else if(tile.uniq < uniq) { - l = mid + 1; - } else { - r = mid - 1; - } - - // before exiting the loop - if (l >= r) { - return get_tile(l); - } - } -} - -vec4 get_tile_color(vec3 pos) { - float delta = asin(pos.y); - float theta = atan(pos.x, pos.z); - HashDxDy result = hash_with_dxdy(vec2(theta, delta)); - - int idx = result.idx; - vec2 uv = vec2(result.dy, result.dx); - //return vec4(uv, 1.0, 1.0); - - int uniq = 16 + idx; - Tile tile = binary_search_tile(uniq); - - int idx_texture = tile.texture_idx / 64; - int off = tile.texture_idx - idx_texture * 64; - - int idx_row = off / 8; // in [0; 7] - int idx_col = off - idx_row * 8; // in [0; 7] - - vec2 offset = (vec2(idx_col, idx_row) + uv) * 0.125; - vec3 UV = vec3(offset.x, offset.y, 0.0); - - vec4 color = get_color_from_texture(UV); - color.a *= (1.0 - float(tile.empty)); - return color; -} - -uniform sampler2D position_tex; -uniform mat4 model; -void main() { - vec2 uv = out_clip_pos * 0.5 + 0.5; - vec3 n = texture2D(position_tex, uv).rgb; - /* Taylor DL - float x = out_clip_pos.x; - float y = out_clip_pos.y; - float x2 = x*x; - float y2 = y*y; - float x4 = x2*x2; - float y4 = y2*y2; - - n = vec3( - -x, - y, - -0.5*x2 - 0.5*y2 + 1.0 - ); - */ - - vec3 frag_pos = vec3(model * vec4(n, 1.0)); - - // Get the HEALPix cell idx and the uv in the texture - vec4 c = get_tile_color(frag_pos); - gl_FragColor = vec4(c.rgb, c.a * opacity); -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/raytracer/grayscale_to_colormap.frag b/src/glsl/webgl1/hips/raytracer/grayscale_to_colormap.frag deleted file mode 100644 index 4ad49271..00000000 --- a/src/glsl/webgl1/hips/raytracer/grayscale_to_colormap.frag +++ /dev/null @@ -1,92 +0,0 @@ -precision mediump float; -precision mediump sampler2D; -precision mediump int; - -varying vec3 out_vert_pos; -varying vec2 out_clip_pos; - -struct Tile { - int uniq; // Healpix cell - int texture_idx; // Index in the texture buffer - float start_time; // Absolute time that the load has been done in ms - float empty; -}; - -uniform Tile textures_tiles[192]; -uniform int num_tiles; - -uniform float current_time; // current time in ms - -@import ../color; -@import ./healpix; - -uniform float opacity; - -Tile get_tile(int idx) { - for(int i = 0; i < 12; i++) { - if( i == idx ) { - return textures_tiles[i]; - } - } -} - -Tile binary_search_tile(int uniq) { - int l = 0; - int r = 11; - for (int v = 0; v <= 5; v++) { - int mid = (l + r) / 2; - - Tile tile = get_tile(mid); - if(tile.uniq == uniq) { - return tile; - } else if(tile.uniq < uniq) { - l = mid + 1; - } else { - r = mid - 1; - } - - // before exiting the loop - if (l >= r) { - return get_tile(l); - } - } -} - -vec4 get_tile_color(vec3 pos) { - float delta = asin(pos.y); - float theta = atan(pos.x, pos.z); - HashDxDy result = hash_with_dxdy(vec2(theta, delta)); - - int idx = result.idx; - vec2 uv = vec2(clamp(result.dy, 0.0, 1.0), result.dx); - int uniq = 16 + idx; - Tile tile = binary_search_tile(uniq); - - int idx_texture = tile.texture_idx / 64; - int off = tile.texture_idx - idx_texture * 64; - - int idx_row = off / 8; // in [0; 7] - int idx_col = off - idx_row * 8; // in [0; 7] - - vec2 offset = (vec2(float(idx_col), float(idx_row)) + uv)*0.125; - vec3 UV = vec3(offset, float(idx_texture)); - - vec4 c = get_colormap_from_grayscale_texture(UV); - // handle empty tiles - vec4 color = mix(c, vec4(0.0), tile.empty); - return color; -} - -uniform sampler2D position_tex; -uniform mat4 model; -void main() { - vec2 uv = out_clip_pos * 0.5 + 0.5; - vec3 n = texture2D(position_tex, uv).rgb; - - vec3 frag_pos = vec3(model * vec4(n, 1.0)); - - vec4 c = get_tile_color(frag_pos); - c.a = c.a * opacity; - - gl_FragColor = c; -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/raytracer/healpix.glsl b/src/glsl/webgl1/hips/raytracer/healpix.glsl deleted file mode 100644 index 6143de3b..00000000 --- a/src/glsl/webgl1/hips/raytracer/healpix.glsl +++ /dev/null @@ -1,20 +0,0 @@ -const float TWICE_PI = 6.28318530718; -const float PI = 3.141592653589793; - -struct HashDxDy { - int idx; - float dx; - float dy; -}; - -uniform sampler2D u_ang2pixd; -HashDxDy hash_with_dxdy(vec2 radec) { - vec2 uv = vec2(radec.x/TWICE_PI, radec.y/PI) + 0.5; - vec3 v = texture2D(u_ang2pixd, uv).rgb; - - return HashDxDy( - int(v.x), - v.y, - v.z - ); -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/raytracer/raytracer.vert b/src/glsl/webgl1/hips/raytracer/raytracer.vert deleted file mode 100644 index 45737de8..00000000 --- a/src/glsl/webgl1/hips/raytracer/raytracer.vert +++ /dev/null @@ -1,13 +0,0 @@ -precision highp float; -precision highp int; - -attribute vec2 pos_clip_space; -varying vec2 out_clip_pos; - -uniform vec2 ndc_to_clip; -uniform float czf; - -void main() { - gl_Position = vec4(pos_clip_space / (ndc_to_clip * czf), 0.0, 1.0); - out_clip_pos = pos_clip_space; -} \ No newline at end of file diff --git a/src/glsl/webgl1/hips/transfer_funcs.glsl b/src/glsl/webgl1/hips/transfer_funcs.glsl deleted file mode 100644 index aa04ba58..00000000 --- a/src/glsl/webgl1/hips/transfer_funcs.glsl +++ /dev/null @@ -1,41 +0,0 @@ -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh(float x) { - return log(x + sqrt(x*x + 1.0)); -} -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} \ No newline at end of file diff --git a/src/glsl/webgl1/line/line_frag.glsl b/src/glsl/webgl1/line/line_frag.glsl deleted file mode 100644 index 10109fc1..00000000 --- a/src/glsl/webgl1/line/line_frag.glsl +++ /dev/null @@ -1,8 +0,0 @@ -precision highp float; -varying vec4 v_rgba; - -void main() { - // Multiply vertex color with texture color (in linear space). - // Linear color is written and blended in Framebuffer and converted to sRGB later - gl_FragColor = v_rgba; -} \ No newline at end of file diff --git a/src/glsl/webgl1/line/line_vertex.glsl b/src/glsl/webgl1/line/line_vertex.glsl deleted file mode 100644 index 7bf53507..00000000 --- a/src/glsl/webgl1/line/line_vertex.glsl +++ /dev/null @@ -1,17 +0,0 @@ -precision highp float; -attribute vec2 pos; - -uniform vec2 u_screen_size; -uniform vec4 u_color; - -varying vec4 v_rgba; - -void main() { - gl_Position = vec4( - pos, - 0.0, - 1.0 - ); - - v_rgba = u_color; -} \ No newline at end of file diff --git a/src/glsl/webgl1/misc/text.frag b/src/glsl/webgl1/misc/text.frag deleted file mode 100644 index 915f1710..00000000 --- a/src/glsl/webgl1/misc/text.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -uniform vec4 text_color; -uniform sampler2DArray font_textures; - -in vec3 out_uv; -out vec4 color; - -void main() { - vec3 uv = vec3(out_uv.x, 1.f - out_uv.y, out_uv.z); - vec4 mask = texture(font_textures, uv); - color = text_color * mask; - //color = vec4(1.0, 0.0, 0.0, 1.0); -} \ No newline at end of file diff --git a/src/glsl/webgl1/misc/text.vert b/src/glsl/webgl1/misc/text.vert deleted file mode 100644 index 500e432e..00000000 --- a/src/glsl/webgl1/misc/text.vert +++ /dev/null @@ -1,32 +0,0 @@ -#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -layout (location = 0) in vec2 pos; -layout (location = 1) in vec2 uv; -// Per instance attributes -layout (location = 2) in vec2 center_letter; -layout (location = 3) in vec2 size_letter; -layout (location = 4) in vec2 pos_uv; -layout (location = 5) in vec2 size_uv; -layout (location = 6) in float idx_page; - -out vec3 out_uv; - -uniform vec2 window_size; -uniform float scaling; - -vec2 screen_to_ndc(vec2 p) { - // Change of origin - vec2 origin = p - window_size/2.0; - - // Scale to fit in [-1, 1] - return vec2(2.0 * (origin.x/window_size.x), -2.0 * (origin.y/window_size.y)); -} - -void main() { - vec2 ndc_pos = screen_to_ndc(center_letter + pos*32.0); - - gl_Position = vec4(ndc_pos, 0.f, 1.f); - out_uv = vec3(uv, idx_page); -} \ No newline at end of file diff --git a/src/glsl/webgl1/passes/post_fragment_100es.glsl b/src/glsl/webgl1/passes/post_fragment_100es.glsl deleted file mode 100644 index 15c69fd9..00000000 --- a/src/glsl/webgl1/passes/post_fragment_100es.glsl +++ /dev/null @@ -1,25 +0,0 @@ -precision mediump float; - -varying vec2 v_tc; -varying vec4 color; - -uniform sampler2D fbo_tex; - -// 0-255 sRGB from 0-1 linear -vec3 srgb_from_linear(vec3 rgb) { - bvec3 cutoff = lessThan(rgb, vec3(0.0031308)); - vec3 lower = rgb * vec3(3294.6); - vec3 higher = vec3(269.025) * pow(rgb, vec3(1.0 / 2.4)) - vec3(14.025); - return mix(higher, lower, vec3(cutoff)); -} - -// 0-255 sRGBA from 0-1 linear -vec4 srgba_from_linear(vec4 rgba) { - return vec4(srgb_from_linear(rgba.rgb), 255.0 * rgba.a); -} - -void main() { - gl_FragColor = texture2D(fbo_tex, v_tc); - - //color = srgba_from_linear(color) / 255.; -} \ No newline at end of file diff --git a/src/glsl/webgl1/passes/post_vertex_100es.glsl b/src/glsl/webgl1/passes/post_vertex_100es.glsl deleted file mode 100644 index 4f1a4b4a..00000000 --- a/src/glsl/webgl1/passes/post_vertex_100es.glsl +++ /dev/null @@ -1,9 +0,0 @@ -precision mediump float; - -attribute vec2 a_pos; -varying vec2 v_tc; - -void main() { - gl_Position = vec4(a_pos * 2. - 1., 0.0, 1.0); - v_tc = a_pos; -} \ No newline at end of file diff --git a/src/glsl/webgl1/text/text_frag.glsl b/src/glsl/webgl1/text/text_frag.glsl deleted file mode 100644 index 122f4393..00000000 --- a/src/glsl/webgl1/text/text_frag.glsl +++ /dev/null @@ -1,17 +0,0 @@ -precision highp float; - -varying vec4 v_rgba; -varying vec2 v_tc; -varying vec4 color; - -uniform sampler2D u_sampler_font; - -void main() { - // The texture is set up with `SRGB8_ALPHA8`, so no need to decode here! - float alpha = texture2D(u_sampler_font, v_tc).r; - - // Multiply vertex color with texture color (in linear space). - // Linear color is written and blended in Framebuffer and converted to sRGB later - gl_FragColor = v_rgba * alpha; - gl_FragColor.a = alpha; -} \ No newline at end of file diff --git a/src/glsl/webgl1/text/text_vertex.glsl b/src/glsl/webgl1/text/text_vertex.glsl deleted file mode 100644 index a5880348..00000000 --- a/src/glsl/webgl1/text/text_vertex.glsl +++ /dev/null @@ -1,24 +0,0 @@ -attribute vec2 pos; -attribute vec2 tx; - -varying vec4 v_rgba; -varying vec2 v_tc; - -uniform vec2 u_screen_size; -uniform vec4 u_color; -uniform vec2 u_screen_pos; -uniform mat2 u_rot; -uniform float u_scale; -uniform float u_dpi; - -void main() { - vec2 p = u_rot * u_scale * u_dpi * pos; - vec2 ndc_pos = vec2( - 2.0 * (p.x + u_screen_pos.x * u_dpi) / u_screen_size.x - 1.0, - 1.0 - 2.0 * (p.y + u_screen_pos.y * u_dpi) / u_screen_size.y - ); - gl_Position = vec4(ndc_pos, 0.0, 1.0); - - v_rgba = u_color; - v_tc = tx; -} \ No newline at end of file diff --git a/src/glsl/webgl2/catalogs/aitoff.vert b/src/glsl/webgl2/catalogs/aitoff.vert index fd32e6f5..141c5627 100644 --- a/src/glsl/webgl2/catalogs/aitoff.vert +++ b/src/glsl/webgl2/catalogs/aitoff.vert @@ -15,7 +15,7 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/arc.vert b/src/glsl/webgl2/catalogs/arc.vert index 762feb94..b9f76e1b 100644 --- a/src/glsl/webgl2/catalogs/arc.vert +++ b/src/glsl/webgl2/catalogs/arc.vert @@ -14,7 +14,7 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/healpix.vert b/src/glsl/webgl2/catalogs/healpix.vert index efd132b4..7b568ff5 100644 --- a/src/glsl/webgl2/catalogs/healpix.vert +++ b/src/glsl/webgl2/catalogs/healpix.vert @@ -15,7 +15,8 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; + void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/mercator.vert b/src/glsl/webgl2/catalogs/mercator.vert index 781f8e27..958d85fd 100644 --- a/src/glsl/webgl2/catalogs/mercator.vert +++ b/src/glsl/webgl2/catalogs/mercator.vert @@ -14,7 +14,8 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; + void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/mollweide.vert b/src/glsl/webgl2/catalogs/mollweide.vert index de291359..20ced43d 100644 --- a/src/glsl/webgl2/catalogs/mollweide.vert +++ b/src/glsl/webgl2/catalogs/mollweide.vert @@ -14,7 +14,8 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; + void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/ortho.vert b/src/glsl/webgl2/catalogs/ortho.vert index f7b5b5f5..95d53caf 100644 --- a/src/glsl/webgl2/catalogs/ortho.vert +++ b/src/glsl/webgl2/catalogs/ortho.vert @@ -14,7 +14,8 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; + void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/catalogs/tan.vert b/src/glsl/webgl2/catalogs/tan.vert index c29cd976..dd7df8c3 100644 --- a/src/glsl/webgl2/catalogs/tan.vert +++ b/src/glsl/webgl2/catalogs/tan.vert @@ -15,7 +15,8 @@ uniform vec2 kernel_size; out vec2 out_uv; out vec3 out_p; -#include ../hips/projection.glsl; +#include ../projection/projection.glsl; + void main() { vec3 p = vec3(inv_model * vec4(center, 1.0f)); diff --git a/src/glsl/webgl2/fits/vert.glsl b/src/glsl/webgl2/fits/base.vert similarity index 100% rename from src/glsl/webgl2/fits/vert.glsl rename to src/glsl/webgl2/fits/base.vert diff --git a/src/glsl/webgl2/fits/frag_isampler.glsl b/src/glsl/webgl2/fits/isampler.frag similarity index 100% rename from src/glsl/webgl2/fits/frag_isampler.glsl rename to src/glsl/webgl2/fits/isampler.frag diff --git a/src/glsl/webgl2/fits/frag_sampler.glsl b/src/glsl/webgl2/fits/sampler.frag similarity index 100% rename from src/glsl/webgl2/fits/frag_sampler.glsl rename to src/glsl/webgl2/fits/sampler.frag diff --git a/src/glsl/webgl2/fits/frag_usampler.glsl b/src/glsl/webgl2/fits/usampler.frag similarity index 100% rename from src/glsl/webgl2/fits/frag_usampler.glsl rename to src/glsl/webgl2/fits/usampler.frag diff --git a/src/glsl/webgl2/grid/grid_cpu.frag b/src/glsl/webgl2/grid/grid_cpu.frag deleted file mode 100644 index b2cb97b4..00000000 --- a/src/glsl/webgl2/grid/grid_cpu.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 300 es -precision lowp float; - -out vec4 frag_color; - -uniform vec3 color; -uniform float opacity; - -const float PI = 3.141592653589793f; - -void main() { - frag_color = vec4(color, opacity); -} \ No newline at end of file diff --git a/src/glsl/webgl2/grid/grid_cpu.vert b/src/glsl/webgl2/grid/grid_cpu.vert deleted file mode 100644 index a401662f..00000000 --- a/src/glsl/webgl2/grid/grid_cpu.vert +++ /dev/null @@ -1,8 +0,0 @@ -#version 300 es -precision lowp float; - -layout (location = 0) in vec2 ndc_pos; - -void main() { - gl_Position = vec4(ndc_pos, 0.0, 1.0); -} \ No newline at end of file diff --git a/src/glsl/webgl2/hips/projection.glsl b/src/glsl/webgl2/hips/projection.glsl deleted file mode 100644 index 7b52a1a6..00000000 --- a/src/glsl/webgl2/hips/projection.glsl +++ /dev/null @@ -1,259 +0,0 @@ -const float PI = 3.1415926535897932384626433832795; - -const mat4 GAL2J2000 = mat4( - -0.4448296299195045, - 0.7469822444763707, - 0.4941094279435681, - 0.0, - - -0.1980763734646737, - 0.4559837762325372, - -0.8676661489811610, - 0.0, - - -0.873437090247923, - -0.4838350155267381, - -0.0548755604024359, - 0.0, - - 0.0, - 0.0, - 0.0, - 1.0 -); - -const mat4 J20002GAL = mat4( - -0.4448296299195045, - -0.1980763734646737, - -0.873437090247923, - 0.0, - - 0.7469822444763707, - 0.4559837762325372, - -0.4838350155267381, - 0.0, - - 0.4941094279435681, - -0.8676661489811610, - -0.0548755604024359, - 0.0, - - 0.0, - 0.0, - 0.0, - 1.0 -); - -vec2 world2clip_orthographic(vec3 p) { - return vec2(-p.x, p.y); -} - - -vec2 world2clip_aitoff(vec3 p) { - float delta = asin(p.y); - float theta = atan(-p.x, p.z); - - float theta_by_two = theta * 0.5; - - float alpha = acos(cos(delta)*cos(theta_by_two)); - float inv_sinc_alpha = 1.0; - if (alpha > 1e-4) { - inv_sinc_alpha = alpha / sin(alpha); - } - //float inv_sinc_alpha = alpha / sin(alpha); - //float inv_sinc_alpha = 1.0; - - // The minus is an astronomical convention. - // longitudes are increasing from right to left - float x = 2.0 * inv_sinc_alpha * cos(delta) * sin(theta_by_two); - float y = inv_sinc_alpha * sin(delta); - - return vec2(x / PI, y / PI); -} - -/* -vec2 world2clip_aitoff(vec3 p) { - //p = normalize(p); - float x = p.z; - float y = -p.x; - float z = p.y; - - float r = sqrt(x * x + y * y); - float w = sqrt(0.5 * r * (r + x)); // = cos(b) cos(l/2) - if (w > 1e-3) { - w = sqrt(0.5 * (1.0 + w)); // = 1 / gamma - } else { - w = sqrt(0.5) * (1.0 + 0.5 * w - w*w*0.125); - } - float y2d = z / w; - w = sqrt(2.0 * r * (r - x)) / w; // = 2 * gamma * cos(b) sin(l/2) - float x2d = w; - if (y < 0.0) { - x2d = -w; - } - //float x2d = y < 0.0 ? -w : w; - return vec2(x2d / PI, y2d / PI); -}*/ - -vec2 world2clip_mollweide(vec3 p) { - // X in [-1, 1] - // Y in [-1/2; 1/2] and scaled by the screen width/height ratio - int max_iter = 10; - - float delta = asin(p.y); - float theta = atan(p.x, p.z); - - float cst = PI * sin(delta); - - float phi = delta; - float dx = phi + sin(phi) - cst; - int k = 0; - while (abs(dx) > 1e-6 && k < max_iter) { - phi = phi - dx / (1.0 + cos(phi)); - dx = phi + sin(phi) - cst; - - k = k + 1; - } - - phi = phi * 0.5; - - // The minus is an astronomical convention. - // longitudes are increasing from right to left - float x = (-theta / PI) * cos(phi); - float y = 0.5 * sin(phi); - - return vec2(x, y); -} - -vec2 world2clip_mercator(vec3 p) { - // X in [-1, 1] - // Y in [-1/2; 1/2] and scaled by the screen width/height ratio - - float delta = asin(p.y); - float theta = atan(-p.x, p.z); - - float x = theta / PI; - float y = asinh(tan(delta / PI)); - - return vec2(x, y); -} - -float arc_sinc(float x) { - if (x > 1e-4) { - return asin(x) / x; - } else { - // If a is mall, use Taylor expension of asin(a) / a - // a = 1e-4 => a^4 = 1.e-16 - float x2 = x*x; - return 1.0 + x2 * (1.0 + x2 * 9.0 / 20.0) / 6.0; - } -} - -vec2 world2clip_arc(vec3 p) { - if (p.z > -1.0) { - // Distance in the Euclidean plane (xy) - // Angular distance is acos(x), but for small separation, asin(r) - // is more accurate. - float r = length(p.xy); - if (p.z > 0.0) { // Angular distance < PI/2, angular distance = asin(r) - r = arc_sinc(r); - } else { // Angular distance > PI/2, angular distance = acos(x) - r = acos(p.z) / r; - } - float x = p.x * r; - float y = p.y * r; - - return vec2(-x / PI, y / PI); - } else { - return vec2(1.0, 0.0); - } -} - -vec2 world2clip_gnomonic(vec3 p) { - if (p.z <= 1e-2) { // Back hemisphere (x < 0) + diverges near x=0 - return vec2(1.0, 0.0); - } else { - return vec2((-p.x/p.z) / PI , (p.y/p.z) / PI); - } -} - -// HEALPix projection -const float TWICE_PI = 6.28318530718; -const float FOUR_OVER_PI = 1.27323954474; -const float TRANSITION_Z = 0.66666666666; -const float TRANSITION_Z_INV = 1.5; - -float one_minus_z_pos(vec3 p) { - //debug_assert!(z > 0.0); - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - - if (d2 < 1e-1) { // <=> dec > 84.27 deg - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); - } - return 1.0 - p.z; -} - -float one_minus_z_neg(vec3 p) { - //debug_assert!(z < 0.0); - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - if (d2 < 1e-1) { // <=> dec < -84.27 deg - // 0.5 * d2 + 0.125 * d2 * d2 - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); - } - return p.z + 1.0; -} - -vec2 xpm1_and_offset(vec2 p) { - int x_neg = int(p.x < 0.0); - //debug_assert!(x_neg <= 1); - int y_neg = int(p.y < 0.0); - //debug_assert!(y_neg <= 1); - int offset = -(y_neg << 2) + 1 + ((x_neg ^ y_neg) << 1); - // The purpose is to have the same numerical precision for each base cell - // by avoiding subtraction by 1.0 or 3.0 or 5.0 or 7.0 - float lon = atan(abs(p.y), abs(p.x)); - //debug_assert!(0.0 <= lon && lon <= PI / 2.0); - float x02 = lon * FOUR_OVER_PI; - //debug_assert!(0.0 <= x02 && x02 <= 2.0); - if (x_neg != y_neg) { // Could be replaced by a sign copy from (x_neg ^ y_neg) << 32 - return vec2(1.0 - x02, float(offset)); - } else { - return vec2(x02 - 1.0, float(offset)); - } -} - -vec2 world2clip_healpix(vec3 p) { - //assert!(depth <= 14); - //assert!(-1.0 <= x && x <= 1.0); - //assert!(-1.0 <= y && y <= 1.0); - //assert!(-1.0 <= z && z <= 1.0); - //debug_assert!(1.0 - (x * x + y * y + z * z) < 1e-5); - // A f32 mantissa contains 23 bits. - // - it basically means that when storing (x, y) coordinates, - // we can go as deep as depth 24 (or maybe 25) - vec2 x_pm1_and_offset = xpm1_and_offset(p.xy); - vec2 p_proj = vec2(0.0); - if (p.z > TRANSITION_Z) { - // North polar cap, Collignon projection. - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_pos(p)); - p_proj = vec2( - (x_pm1_and_offset.x * sqrt_3_one_min_z) + x_pm1_and_offset.y, - 2.0 - sqrt_3_one_min_z - ); - } else if (p.z < -TRANSITION_Z) { - // South polar cap, Collignon projection - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_neg(p)); - p_proj = vec2( - (x_pm1_and_offset.x * sqrt_3_one_min_z) + x_pm1_and_offset.y, - -2.0 + sqrt_3_one_min_z - ); - } else { - // Equatorial region, Cylindrical equal area projection - p_proj = vec2( - atan(p.y, p.x) * FOUR_OVER_PI, - p.z * TRANSITION_Z_INV - ); - } - - return p_proj * vec2(-0.25, 0.5); -} \ No newline at end of file diff --git a/src/glsl/webgl2/hips/rasterizer/raster.vert b/src/glsl/webgl2/hips/rasterizer/raster.vert index 4a77577a..ab7c78d8 100644 --- a/src/glsl/webgl2/hips/rasterizer/raster.vert +++ b/src/glsl/webgl2/hips/rasterizer/raster.vert @@ -16,15 +16,9 @@ out float frag_blending_factor; out float m_start; out float m_end; -uniform mat4 inv_model; -uniform vec2 ndc_to_clip; -uniform float czf; - // current time in ms uniform float current_time; -#include ../projection.glsl; - void main() { gl_Position = vec4(ndc_pos, 0.0, 1.0); diff --git a/src/glsl/webgl2/hips/raytracer/color.frag b/src/glsl/webgl2/hips/raytracer/color.frag index c65ce6f9..fe089493 100644 --- a/src/glsl/webgl2/hips/raytracer/color.frag +++ b/src/glsl/webgl2/hips/raytracer/color.frag @@ -19,7 +19,7 @@ struct Tile { uniform Tile textures_tiles[12]; #include ../color.glsl; -#include ./healpix.glsl; +#include ../../projection/hpx.glsl; uniform float opacity; diff --git a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap.frag b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap.frag index b17d433b..9e1df202 100644 --- a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap.frag +++ b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap.frag @@ -26,7 +26,7 @@ struct TileColor { }; #include ../color.glsl; -#include ./healpix.glsl; +#include ../../projection/hpx.glsl; vec4 get_tile_color(vec3 pos) { HashDxDy result = hash_with_dxdy(0, pos.zxy); diff --git a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_i.frag b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_i.frag index e3ce8296..88b0bb11 100644 --- a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_i.frag +++ b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_i.frag @@ -21,7 +21,7 @@ uniform Tile textures_tiles[12]; uniform float opacity; #include ../color_i.glsl; -#include ./healpix.glsl; +#include ../../projection/hpx.glsl; vec4 get_tile_color(vec3 pos) { HashDxDy result = hash_with_dxdy(0, pos.zxy); diff --git a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_u.frag b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_u.frag index d56c541d..7865d7c6 100644 --- a/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_u.frag +++ b/src/glsl/webgl2/hips/raytracer/grayscale_to_colormap_u.frag @@ -21,7 +21,7 @@ uniform Tile textures_tiles[12]; uniform float opacity; #include ../color_u.glsl; -#include ./healpix.glsl; +#include ../../projection/hpx.glsl; vec4 get_tile_color(vec3 pos) { HashDxDy result = hash_with_dxdy(0, pos.zxy); diff --git a/src/glsl/webgl2/hips/raytracer/raytracer.vert b/src/glsl/webgl2/hips/raytracer/raytracer.vert index 1b60b1ce..316f7017 100644 --- a/src/glsl/webgl2/hips/raytracer/raytracer.vert +++ b/src/glsl/webgl2/hips/raytracer/raytracer.vert @@ -8,11 +8,9 @@ out vec3 frag_pos; uniform vec2 ndc_to_clip; uniform float czf; - uniform mat4 model; -uniform sampler2D position_tex; -#include ../projection.glsl; +uniform sampler2D position_tex; void main() { vec2 uv = pos_clip_space * 0.5 + 0.5; diff --git a/src/glsl/webgl2/line/line_frag.glsl b/src/glsl/webgl2/line/base.frag similarity index 65% rename from src/glsl/webgl2/line/line_frag.glsl rename to src/glsl/webgl2/line/base.frag index cae193a5..4356da4e 100644 --- a/src/glsl/webgl2/line/line_frag.glsl +++ b/src/glsl/webgl2/line/base.frag @@ -1,12 +1,17 @@ #version 300 es precision lowp float; -in vec4 v_rgba; - out vec4 color; +in float l; + +uniform vec4 u_color; void main() { // Multiply vertex color with texture color (in linear space). // Linear color is written and blended in Framebuffer and converted to sRGB later - color = v_rgba; + if (l > 0.025) { + discard; + } else { + color = u_color; + } } \ No newline at end of file diff --git a/src/glsl/webgl2/line/line_vertex.glsl b/src/glsl/webgl2/line/base.vert similarity index 72% rename from src/glsl/webgl2/line/line_vertex.glsl rename to src/glsl/webgl2/line/base.vert index 3b7e359b..fef41d55 100644 --- a/src/glsl/webgl2/line/line_vertex.glsl +++ b/src/glsl/webgl2/line/base.vert @@ -2,9 +2,7 @@ precision lowp float; layout (location = 0) in vec2 ndc_pos; -uniform vec4 u_color; - -out vec4 v_rgba; +out float l; void main() { gl_Position = vec4( @@ -12,6 +10,4 @@ void main() { 0.0, 1.0 ); - - v_rgba = u_color; } \ No newline at end of file diff --git a/src/glsl/webgl2/line/inst_lonlat.vert b/src/glsl/webgl2/line/inst_lonlat.vert new file mode 100644 index 00000000..e37383c6 --- /dev/null +++ b/src/glsl/webgl2/line/inst_lonlat.vert @@ -0,0 +1,79 @@ +#version 300 es +precision highp float; +layout (location = 0) in vec2 p_a_lonlat; +layout (location = 1) in vec2 p_b_lonlat; +layout (location = 2) in vec2 vertex; + +uniform mat4 u_2world; +uniform vec2 ndc_to_clip; +uniform float czf; +uniform float u_width; +uniform int u_proj; + +out float l; + +#include ../projection/projection.glsl; + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +vec2 proj(vec3 p) { + if (u_proj == 0) { + /* TAN, Gnomonic projection */ + return w2c_tan(p); + } else if (u_proj == 1) { + /* STG, Stereographic projection */ + return w2c_stg(p); + } else if (u_proj == 2) { + /* SIN, Orthographic */ + return w2c_sin(p); + } else if (u_proj == 3) { + /* ZEA, Equal-area */ + return w2c_zea(p); + } else if (u_proj == 4) { + // Pseudo-cylindrical projections + /* AIT, Aitoff */ + return w2c_ait(p); + } else if (u_proj == 5) { + // MOL, Mollweide */ + return w2c_mol(p); + } else { + // Cylindrical projections + // MER, Mercator */ + return w2c_mer(p); + } +} + +void main() { + // 1. Convert (lon, lat) into (x, y, z) space coo. + vec3 p_a_xyz = lonlat2xyz(p_a_lonlat); + vec3 p_b_xyz = lonlat2xyz(p_b_lonlat); + // 2. Convert to the world coo system + vec4 p_a_w = u_2world * vec4(p_a_xyz, 1.0); + vec4 p_b_w = u_2world * vec4(p_b_xyz, 1.0); + // 3. Process the projection + vec2 p_a_clip = proj(p_a_w.xyz); + vec2 p_b_clip = proj(p_b_w.xyz); + + vec2 da = p_a_clip - p_b_clip; + + l = da.x*da.x + da.y*da.y; + vec2 p_a_ndc = p_a_clip / (ndc_to_clip * czf); + vec2 p_b_ndc = p_b_clip / (ndc_to_clip * czf); + + // 4. Determine the final position + vec2 x_b = p_b_ndc - p_a_ndc; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + vec2 p_ndc = p_a_ndc + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y; + gl_Position = vec4(p_ndc, 0.f, 1.f); +} \ No newline at end of file diff --git a/src/glsl/webgl2/line/inst_ndc.vert b/src/glsl/webgl2/line/inst_ndc.vert new file mode 100644 index 00000000..f12f6f54 --- /dev/null +++ b/src/glsl/webgl2/line/inst_ndc.vert @@ -0,0 +1,17 @@ +#version 300 es +precision lowp float; +layout (location = 0) in vec2 p_a; +layout (location = 1) in vec2 p_b; +layout (location = 2) in vec2 vertex; + +out float l; + +uniform float u_width; + +void main() { + vec2 x_b = p_b - p_a; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y; + gl_Position = vec4(p, 0.f, 1.f); +} \ No newline at end of file diff --git a/src/glsl/webgl2/misc/text.frag b/src/glsl/webgl2/misc/text.frag deleted file mode 100644 index 915f1710..00000000 --- a/src/glsl/webgl2/misc/text.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -uniform vec4 text_color; -uniform sampler2DArray font_textures; - -in vec3 out_uv; -out vec4 color; - -void main() { - vec3 uv = vec3(out_uv.x, 1.f - out_uv.y, out_uv.z); - vec4 mask = texture(font_textures, uv); - color = text_color * mask; - //color = vec4(1.0, 0.0, 0.0, 1.0); -} \ No newline at end of file diff --git a/src/glsl/webgl2/misc/text.vert b/src/glsl/webgl2/misc/text.vert deleted file mode 100644 index 500e432e..00000000 --- a/src/glsl/webgl2/misc/text.vert +++ /dev/null @@ -1,32 +0,0 @@ -#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -layout (location = 0) in vec2 pos; -layout (location = 1) in vec2 uv; -// Per instance attributes -layout (location = 2) in vec2 center_letter; -layout (location = 3) in vec2 size_letter; -layout (location = 4) in vec2 pos_uv; -layout (location = 5) in vec2 size_uv; -layout (location = 6) in float idx_page; - -out vec3 out_uv; - -uniform vec2 window_size; -uniform float scaling; - -vec2 screen_to_ndc(vec2 p) { - // Change of origin - vec2 origin = p - window_size/2.0; - - // Scale to fit in [-1, 1] - return vec2(2.0 * (origin.x/window_size.x), -2.0 * (origin.y/window_size.y)); -} - -void main() { - vec2 ndc_pos = screen_to_ndc(center_letter + pos*32.0); - - gl_Position = vec4(ndc_pos, 0.f, 1.f); - out_uv = vec3(uv, idx_page); -} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/ait.glsl b/src/glsl/webgl2/projection/ait.glsl new file mode 100644 index 00000000..8b18713d --- /dev/null +++ b/src/glsl/webgl2/projection/ait.glsl @@ -0,0 +1,18 @@ + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 1e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} diff --git a/src/glsl/webgl2/hips/raytracer/healpix.glsl b/src/glsl/webgl2/projection/hpx.glsl similarity index 100% rename from src/glsl/webgl2/hips/raytracer/healpix.glsl rename to src/glsl/webgl2/projection/hpx.glsl diff --git a/src/glsl/webgl2/projection/mer.glsl b/src/glsl/webgl2/projection/mer.glsl new file mode 100644 index 00000000..6c962b6b --- /dev/null +++ b/src/glsl/webgl2/projection/mer.glsl @@ -0,0 +1,3 @@ +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/mol.glsl b/src/glsl/webgl2/projection/mol.glsl new file mode 100644 index 00000000..e5556477 --- /dev/null +++ b/src/glsl/webgl2/projection/mol.glsl @@ -0,0 +1,26 @@ +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + // Initial guess so that for z ~= 1, gamma ~= PI/2. + // Smooth function for small |z|, so no big deal having a bad init value. + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/projection.glsl b/src/glsl/webgl2/projection/projection.glsl new file mode 100644 index 00000000..469042bd --- /dev/null +++ b/src/glsl/webgl2/projection/projection.glsl @@ -0,0 +1,11 @@ +/// Projections +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +#include ./sin.glsl; +#include ./ait.glsl; +#include ./mol.glsl; +#include ./tan.glsl; +#include ./stg.glsl; +#include ./zea.glsl; +#include ./mer.glsl; \ No newline at end of file diff --git a/src/glsl/webgl2/projection/sin.glsl b/src/glsl/webgl2/projection/sin.glsl new file mode 100644 index 00000000..c21188e2 --- /dev/null +++ b/src/glsl/webgl2/projection/sin.glsl @@ -0,0 +1,4 @@ +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/stg.glsl b/src/glsl/webgl2/projection/stg.glsl new file mode 100644 index 00000000..bc299939 --- /dev/null +++ b/src/glsl/webgl2/projection/stg.glsl @@ -0,0 +1,4 @@ +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/tan.glsl b/src/glsl/webgl2/projection/tan.glsl new file mode 100644 index 00000000..cbc3d13e --- /dev/null +++ b/src/glsl/webgl2/projection/tan.glsl @@ -0,0 +1,3 @@ +vec2 w2c_tan(vec3 p) { + return vec2(-p.x, p.y) / (p.z*PI); +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/zea.glsl b/src/glsl/webgl2/projection/zea.glsl new file mode 100644 index 00000000..62971f0d --- /dev/null +++ b/src/glsl/webgl2/projection/zea.glsl @@ -0,0 +1,5 @@ +vec2 w2c_zea(vec3 p) { + // Whole sphere, r <= 2 (equal area) + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} \ No newline at end of file diff --git a/src/js/ShadersWebGL1.js b/src/js/ShadersWebGL1.js deleted file mode 100644 index b41e6f1a..00000000 --- a/src/js/ShadersWebGL1.js +++ /dev/null @@ -1,126 +0,0 @@ -/* Import all the shaders here*/ -// Catalog shaders -import CatalogAitoffVS from '../glsl/webgl1/catalogs/aitoff.vert'; -import CatalogMercatVS from '../glsl/webgl1/catalogs/mercator.vert'; -import CatalogArcVS from '../glsl/webgl1/catalogs/arc.vert'; -import CatalogTanVS from '../glsl/webgl1/catalogs/tan.vert'; -import CatalogMollVS from '../glsl/webgl1/catalogs/mollweide.vert'; -import CatalogOrthoVS from '../glsl/webgl1/catalogs/ortho.vert'; -import CatalogOrthoFS from '../glsl/webgl1/catalogs/ortho.frag'; -import CatalogFS from '../glsl/webgl1/catalogs/catalog.frag'; - -// Colormap shaders -import ColormapCatalogVS from '../glsl/webgl1/colormaps/colormap.vert' -import ColormapCatalogFS from '../glsl/webgl1/colormaps/colormap.frag' - -// Grid shader -import GridVS_CPU from '../glsl/webgl1/grid/grid_cpu.vert' -import GridFS_CPU from '../glsl/webgl1/grid/grid_cpu.frag' - -// HiPS shaders -// Raytracer -import RayTracerVS from '../glsl/webgl1/hips/raytracer/raytracer.vert' -import RayTracerColorFS from '../glsl/webgl1/hips/raytracer/color.frag' -import RayTracerGrayscale2ColormapFS from '../glsl/webgl1/hips/raytracer/grayscale_to_colormap.frag' -// Rasterizer -import RasterizerVS from '../glsl/webgl1/hips/rasterizer/raster.vert' -import RasterizerColorFS from '../glsl/webgl1/hips/rasterizer/color.frag' -import RasterizerGrayscale2ColormapFS from '../glsl/webgl1/hips/rasterizer/grayscale_to_colormap.frag' - -// Post -import PostVS from '../glsl/webgl1/passes/post_vertex_100es.glsl' -import PostFS from '../glsl/webgl1/passes/post_fragment_100es.glsl' - -let shaders = [ - // Catalog shaders - { - id: "CatalogAitoffVS", - content: CatalogAitoffVS, - }, - { - id: "CatalogMercatVS", - content: CatalogMercatVS, - }, - { - id: "CatalogArcVS", - content: CatalogArcVS, - }, - { - id: "CatalogTanVS", - content: CatalogTanVS, - }, - { - id: "CatalogMollVS", - content: CatalogMollVS, - }, - { - id: "CatalogOrthoVS", - content: CatalogOrthoVS, - }, - { - id: "CatalogOrthoFS", - content: CatalogOrthoFS, - }, - { - id: "CatalogFS", - content: CatalogFS, - }, - // Colormap shaders - { - id: "ColormapCatalogVS", - content: ColormapCatalogVS, - }, - { - id: "ColormapCatalogFS", - content: ColormapCatalogFS, - }, - // Grid shader - { - id: "GridFS_CPU", - content: GridFS_CPU, - }, - { - id: "GridVS_CPU", - content: GridVS_CPU, - }, - // HiPS shaders - // Raytracer - { - id: "RayTracerVS", - content: RayTracerVS, - }, - { - id: "RayTracerColorFS", - content: RayTracerColorFS, - }, - { - id: "RayTracerGrayscale2ColormapFS", - content: RayTracerGrayscale2ColormapFS, - }, - /// Rasterizer - { - id: "RasterizerVS", - content: RasterizerVS, - }, - { - id: "RasterizerColorFS", - content: RasterizerColorFS, - }, - { - id: "RasterizerGrayscale2ColormapFS", - content: RasterizerGrayscale2ColormapFS, - }, - // Post - { - id: "PostVS", - content: PostVS, - }, - { - id: "PostFS", - content: PostFS, - }, -]; - -export function loadShadersWebGL1() { - return shaders; -} diff --git a/src/js/ShadersWebGL2.js b/src/js/ShadersWebGL2.js deleted file mode 100644 index ba02b00d..00000000 --- a/src/js/ShadersWebGL2.js +++ /dev/null @@ -1,185 +0,0 @@ -/* Import all the shaders here*/ -// Catalog shaders -import CatalogAitoffVS from '../glsl/webgl2/catalogs/aitoff.vert'; -import CatalogMercatVS from '../glsl/webgl2/catalogs/mercator.vert'; -import CatalogArcVS from '../glsl/webgl2/catalogs/arc.vert'; -import CatalogTanVS from '../glsl/webgl2/catalogs/tan.vert'; -import CatalogMollVS from '../glsl/webgl2/catalogs/mollweide.vert'; -import CatalogHEALPixVS from '../glsl/webgl2/catalogs/healpix.vert'; -import CatalogOrthoVS from '../glsl/webgl2/catalogs/ortho.vert'; -import CatalogOrthoFS from '../glsl/webgl2/catalogs/ortho.frag'; -import CatalogFS from '../glsl/webgl2/catalogs/catalog.frag'; - -// Colormap shaders -import ColormapCatalogVS from '../glsl/webgl2/colormaps/colormap.vert' -import ColormapCatalogFS from '../glsl/webgl2/colormaps/colormap.frag' - -// Grid shader -import GridVS_CPU from '../glsl/webgl2/grid/grid_cpu.vert' -import GridFS_CPU from '../glsl/webgl2/grid/grid_cpu.frag' - -// HiPS shaders -// Raytracer -import RayTracerVS from '../glsl/webgl2/hips/raytracer/raytracer.vert' -import RayTracerColorFS from '../glsl/webgl2/hips/raytracer/color.frag' -import RayTracerGrayscale2ColormapFS from '../glsl/webgl2/hips/raytracer/grayscale_to_colormap.frag' -import RayTracerGrayscale2ColormapIntegerFS from '../glsl/webgl2/hips/raytracer/grayscale_to_colormap_i.frag' -import RayTracerGrayscale2ColormapUnsignedFS from '../glsl/webgl2/hips/raytracer/grayscale_to_colormap_u.frag' -import RayTracerFontVS from '../glsl/webgl2/hips/raytracer/backcolor.vert' -import RayTracerFontFS from '../glsl/webgl2/hips/raytracer/backcolor.frag' - -// Rasterizer -import RasterizerVS from '../glsl/webgl2/hips/rasterizer/raster.vert' -import RasterizerColorFS from '../glsl/webgl2/hips/rasterizer/color.frag' -import RasterizerGrayscale2ColormapFS from '../glsl/webgl2/hips/rasterizer/grayscale_to_colormap.frag' -import RasterizerGrayscale2ColormapIntegerFS from '../glsl/webgl2/hips/rasterizer/grayscale_to_colormap_i.frag' -import RasterizerGrayscale2ColormapUnsignedFS from '../glsl/webgl2/hips/rasterizer/grayscale_to_colormap_u.frag' - -// Shader passes -import PostVS from '../glsl/webgl2/passes/post_vertex_100es.glsl' -import PostFS from '../glsl/webgl2/passes/post_fragment_100es.glsl' - -// Shader fits image -import FitsVS from '../glsl/webgl2/fits/vert.glsl' -import FitsFS from '../glsl/webgl2/fits/frag_sampler.glsl' -import FitsFSUnsigned from '../glsl/webgl2/fits/frag_usampler.glsl' -import FitsFSInteger from '../glsl/webgl2/fits/frag_isampler.glsl' - -let shaders = [ - // Catalog shaders - { - id: "CatalogAitoffVS", - content: CatalogAitoffVS, - }, - { - id: "CatalogHEALPixVS", - content: CatalogHEALPixVS, - }, - { - id: "CatalogMercatVS", - content: CatalogMercatVS, - }, - { - id: "CatalogArcVS", - content: CatalogArcVS, - }, - { - id: "CatalogTanVS", - content: CatalogTanVS, - }, - { - id: "CatalogMollVS", - content: CatalogMollVS, - }, - { - id: "CatalogOrthoVS", - content: CatalogOrthoVS, - }, - { - id: "CatalogOrthoFS", - content: CatalogOrthoFS, - }, - { - id: "CatalogFS", - content: CatalogFS, - }, - // Colormap shaders - { - id: "ColormapCatalogVS", - content: ColormapCatalogVS, - }, - { - id: "ColormapCatalogFS", - content: ColormapCatalogFS, - }, - // Grid shader - { - id: "GridVS_CPU", - content: GridVS_CPU, - }, - { - id: "GridFS_CPU", - content: GridFS_CPU, - }, - // HiPS shaders - // Raytracer - { - id: "RayTracerVS", - content: RayTracerVS, - }, - { - id: "RayTracerColorFS", - content: RayTracerColorFS, - }, - { - id: "RayTracerGrayscale2ColormapFS", - content: RayTracerGrayscale2ColormapFS, - }, - { - id: "RayTracerGrayscale2ColormapIntegerFS", - content: RayTracerGrayscale2ColormapIntegerFS, - }, - { - id: "RayTracerGrayscale2ColormapUnsignedFS", - content: RayTracerGrayscale2ColormapUnsignedFS, - }, - { - id: "RayTracerFontVS", - content: RayTracerFontVS, - }, - { - id: "RayTracerFontFS", - content: RayTracerFontFS, - }, - /// Rasterizer - { - id: "RasterizerVS", - content: RasterizerVS, - }, - { - id: "RasterizerColorFS", - content: RasterizerColorFS, - }, - { - id: "RasterizerGrayscale2ColormapFS", - content: RasterizerGrayscale2ColormapFS, - }, - { - id: "RasterizerGrayscale2ColormapIntegerFS", - content: RasterizerGrayscale2ColormapIntegerFS, - }, - { - id: "RasterizerGrayscale2ColormapUnsignedFS", - content: RasterizerGrayscale2ColormapUnsignedFS, - }, - // Post - { - id: "PostVS", - content: PostVS, - }, - { - id: "PostFS", - content: PostFS, - }, - // Fits - { - id: "FitsVS", - content: FitsVS, - }, - { - id: "FitsFS", - content: FitsFS, - }, - { - id: "FitsFSUnsigned", - content: FitsFSUnsigned, - }, - { - id: "FitsFSInteger", - content: FitsFSInteger, - }, -]; - -export function loadShadersWebGL2() { - return shaders; -} diff --git a/src/js/WebGL.js b/src/js/WebGL.js index 54c53322..5d49e6ae 100644 --- a/src/js/WebGL.js +++ b/src/js/WebGL.js @@ -1,15 +1,11 @@ -import { loadShadersWebGL2 } from "./ShadersWebGL2.js"; // Import resources images import kernel from '../img/kernel.png'; export let WebGLCtx = (function() { // constructor function WebGLCtx(ctx, div) { - const shaders = loadShadersWebGL2(); - this.webclient = new ctx.WebClient( div, - shaders, { 'kernel': kernel, } From 1ad97180f3d4dff8a8b4e0179ba1bceb74740032 Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 25 Jun 2024 11:32:45 +0200 Subject: [PATCH 04/12] move rendering part from line rasterizer to the moc renderable --- examples/al-moc-sdss9.html | 2 +- src/core/al-core/src/object/buffer_data.rs | 17 + src/core/src/app.rs | 20 +- src/core/src/camera/view_hpx_cells.rs | 121 +++-- src/core/src/camera/viewport.rs | 27 +- src/core/src/healpix/cell.rs | 1 + src/core/src/renderable/catalog/manager.rs | 5 +- src/core/src/renderable/coverage/hierarchy.rs | 8 +- src/core/src/renderable/coverage/moc.rs | 472 ++++++++++++------ src/core/src/renderable/coverage/mod.rs | 65 +-- src/core/src/renderable/hips/mod.rs | 114 +++-- src/core/src/renderable/line/mod.rs | 1 - src/core/src/renderable/mod.rs | 1 - src/core/src/renderable/utils/index_patch.rs | 1 - src/core/src/shader.rs | 5 +- src/glsl/webgl2/hips/rasterizer/raster.vert | 15 +- src/glsl/webgl2/line/base.frag | 2 +- src/glsl/webgl2/line/inst_lonlat.vert | 42 +- src/glsl/webgl2/moc/base.frag | 12 + src/glsl/webgl2/moc/base.vert | 21 + src/glsl/webgl2/projection/hpx.glsl | 2 +- src/glsl/webgl2/projection/projection.glsl | 43 +- src/glsl/webgl2/projection/sin.glsl | 4 + src/glsl/webgl2/projection/tan.glsl | 1 + src/js/MOC.js | 12 + src/js/gui/Box/StackBox.js | 2 +- 26 files changed, 633 insertions(+), 383 deletions(-) create mode 100644 src/glsl/webgl2/moc/base.frag create mode 100644 src/glsl/webgl2/moc/base.vert diff --git a/examples/al-moc-sdss9.html b/examples/al-moc-sdss9.html index 831a94b5..424f1e1b 100644 --- a/examples/al-moc-sdss9.html +++ b/examples/al-moc-sdss9.html @@ -18,7 +18,7 @@ console.log(moc.contains(205.9019247, +2.4492764)); console.log(moc.contains(-205.9019247, +2.4492764)); }); - var moc10 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=11&fmt=fits', {color: '#ffffff', perimeter: true, fillColor: '#aabbcc', opacity: 0.1, lineWidth: 3}); + var moc10 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=11&fmt=fits', {color: '#ffffff', perimeter: true, fillColor: '#aabbcc', opacity: 0.3, lineWidth: 3}); var moc9 = A.MOCFromURL('https://alasky.unistra.fr/MocServer/query?ivorn=ivo%3A%2F%2FCDS%2FV%2F139%2Fsdss9&get=moc&order=4&fmt=fits', {color: '#00ff00', opacity: 0.5, lineWidth: 3, perimeter: true}); aladin.addMOC(moc11); diff --git a/src/core/al-core/src/object/buffer_data.rs b/src/core/al-core/src/object/buffer_data.rs index 65df0f3d..18a5068f 100644 --- a/src/core/al-core/src/object/buffer_data.rs +++ b/src/core/al-core/src/object/buffer_data.rs @@ -41,3 +41,20 @@ where self.0.as_ptr() } } + +impl<'a, T> BufferDataStorage<'a, T> for &'a [T] +where + T: VertexAttribPointerType, +{ + fn get_slice(&self) -> &[T] { + self + } + + fn len(&self) -> usize { + self.len() + } + + fn ptr(&self) -> *const T { + self.as_ptr() + } +} diff --git a/src/core/src/app.rs b/src/core/src/app.rs index c0f1a73d..ebaa40da 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -145,6 +145,7 @@ impl App { //gl.enable(WebGl2RenderingContext::CULL_FACE); //gl.cull_face(WebGl2RenderingContext::BACK); + //gl.enable(WebGl2RenderingContext::CULL_FACE); // The tile buffer responsible for the tile requests let downloader = Downloader::new(); @@ -190,7 +191,7 @@ impl App { let request_for_new_tiles = true; - let moc = MOCRenderer::new()?; + let moc = MOCRenderer::new(&gl)?; gl.clear_color(0.15, 0.15, 0.15, 1.0); let (fits_send, fits_recv) = async_channel::unbounded::(); @@ -522,12 +523,7 @@ impl App { pub(crate) fn set_moc_cfg(&mut self, cfg: al_api::moc::MOC) -> Result<(), JsValue> { self.moc - .set_cfg( - cfg, - &mut self.camera, - &self.projection, - &mut self.line_renderer, - ) + .set_cfg(cfg, &mut self.camera, &self.projection, &mut self.shaders) .ok_or_else(|| JsValue::from_str("MOC not found"))?; self.request_redraw = true; @@ -957,21 +953,21 @@ impl App { &self.colormaps, &self.projection, )?; - use al_core::log::console_log; // Draw the catalog //let fbo_view = &self.fbo_view; //catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?; //catalogs.draw(&gl, shaders, camera, colormaps, None, self.projection)?; - self.line_renderer.begin(); - //Time::measure_perf("moc draw", || { self.moc.draw( - &mut self.shaders, &mut self.camera, &self.projection, - &mut self.line_renderer, + &mut self.shaders, + //&mut self.line_renderer, ); + self.line_renderer.begin(); + //Time::measure_perf("moc draw", || { + // Ok(()) //})?; diff --git a/src/core/src/camera/view_hpx_cells.rs b/src/core/src/camera/view_hpx_cells.rs index 5c78f4b7..14125ead 100644 --- a/src/core/src/camera/view_hpx_cells.rs +++ b/src/core/src/camera/view_hpx_cells.rs @@ -9,6 +9,8 @@ use crate::HEALPixCoverage; use std::ops::Range; +use moclib::moc::{range::op::degrade::degrade, RangeMOCIterator}; + pub(super) struct ViewHpxCells { hpx_cells: [HpxCells; NUM_COOSYSTEM], reg_frames: [u8; NUM_COOSYSTEM], @@ -82,28 +84,38 @@ impl ViewHpxCells { } } - pub(super) fn get_cells<'a>( - &'a mut self, - depth: u8, - frame: CooSystem, - ) -> impl Iterator { + pub(super) fn get_cells(&self, depth: u8, frame: CooSystem) -> Vec { self.hpx_cells[frame as usize].get_cells(depth) } pub(super) fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage { self.hpx_cells[frame as usize].get_cov() } + + /*pub(super) fn has_changed(&mut self) -> bool { + let mut c = false; + for (frame, num_req) in self.reg_frames.iter().enumerate() { + // if there are surveys/camera requesting the coverage + if *num_req > 0 { + c |= self.hpx_cells[frame].has_view_changed(); + } + } + + c + }*/ } // Contains the cells being in the FOV for a specific pub struct HpxCells { frame: CooSystem, // the set of cells all depth - cells: Vec, + //cells: Vec, // An index vector referring to the indices of each depth cells - idx_rng: [Option>; MAX_HPX_DEPTH as usize + 1], + //idx_rng: [Option>; MAX_HPX_DEPTH as usize + 1], // Coverage created in the frame cov: HEALPixCoverage, + // boolean refering to if the cells in the view has changed + //new_cells: bool, } impl Default for HpxCells { @@ -113,22 +125,23 @@ impl Default for HpxCells { } use al_api::coo_system::{CooSystem, NUM_COOSYSTEM}; +use moclib::moc::RangeMOCIntoIterator; use super::FieldOfView; impl HpxCells { pub fn new(frame: CooSystem) -> Self { - let cells = Vec::new(); + //let cells = Vec::new(); let cov = HEALPixCoverage::empty(29); - let idx_rng = Default::default(); + //let idx_rng = Default::default(); Self { - cells, - - idx_rng, + //cells, + //idx_rng, cov, frame, + //new_cells: true, } } @@ -149,63 +162,72 @@ impl HpxCells { super::build_fov_coverage(camera_depth, fov, center, camera_frame, self.frame, proj); // Clear the old cells - self.cells.clear(); + /*let r = self.idx_rng[camera_depth as usize] + .as_ref() + .unwrap_or(&(0..0)); + let old_cells = &self.cells[r.clone()]; + self.idx_rng = Default::default(); + let mut new_cells = false; // Compute the cells at the tile_depth - let tile_depth_cells_iter = self + let cells = self .cov .flatten_to_fixed_depth_cells() - .map(|idx| HEALPixCell(camera_depth, idx)); + .enumerate() + .map(|(j, idx)| { + let c = HEALPixCell(camera_depth, idx); - let num_past = self.cells.len(); - self.cells.extend(tile_depth_cells_iter); + if j >= old_cells.len() || old_cells[j] != c { + new_cells = true; + } + + c + }) + .collect::>(); + + if cells.len() != old_cells.len() { + new_cells = true; + } + + self.cells = cells; let num_cur = self.cells.len(); + self.idx_rng[camera_depth as usize] = Some(0..num_cur); - self.idx_rng[camera_depth as usize] = Some(num_past..num_cur); + if new_cells { + self.new_cells = true; + }*/ } // Accessors // depth MUST be < to camera tile depth - pub fn get_cells<'a>(&'a mut self, depth: u8) -> impl Iterator { - let Range { start, end } = if let Some(idx) = self.idx_rng[depth as usize].as_ref() { - idx.start..idx.end + pub fn get_cells(&self, depth: u8) -> Vec { + let cov_depth = self.cov.depth_max(); + + if depth == cov_depth { + self.cov + .flatten_to_fixed_depth_cells() + .map(move |idx| HEALPixCell(depth, idx)) + .collect() } else if depth > self.cov.depth_max() { let cov_d = self.cov.depth_max(); let dd = depth - cov_d; // compute the cells from the coverage - let cells_iter = self - .cov + + self.cov .flatten_to_fixed_depth_cells() - .map(|idx| { + .flat_map(move |idx| { // idx is at depth_max HEALPixCell(cov_d, idx).get_children_cells(dd) }) - .flatten(); - // add them and store the cells for latter reuse - let num_past = self.cells.len(); - self.cells.extend(cells_iter); - let num_cur = self.cells.len(); - - self.idx_rng[depth as usize] = Some(num_past..num_cur); - num_past..num_cur + .collect() } else { // compute the cells from the coverage - let degraded_moc = self.cov.degraded(depth); - let cells_iter = degraded_moc + degrade((&self.cov.0).into_range_moc_iter(), depth) .flatten_to_fixed_depth_cells() - .map(|idx| HEALPixCell(depth, idx)); - - // add them and store the cells for latter reuse - let num_past = self.cells.len(); - self.cells.extend(cells_iter); - let num_cur = self.cells.len(); - - self.idx_rng[depth as usize] = Some(num_past..num_cur); - num_past..num_cur - }; - - self.cells[start..end].iter() + .map(move |idx| HEALPixCell(depth, idx)) + .collect() + } } /* @@ -250,8 +272,9 @@ impl HpxCells { }*/ /*#[inline] - pub fn has_view_changed(&self) -> bool { - //self.new_cells.is_there_new_cells_added() - !self.view_unchanged + pub fn has_view_changed(&mut self) -> bool { + let new_cells = self.new_cells; + self.new_cells = false; + new_cells }*/ } diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs index 25cc9e7e..27d0a7e9 100644 --- a/src/core/src/camera/viewport.rs +++ b/src/core/src/camera/viewport.rs @@ -209,15 +209,15 @@ impl CameraViewPort { ); } + /*pub fn has_new_hpx_cells(&mut self) -> bool { + self.view_hpx_cells.has_changed() + }*/ + pub fn get_cov(&self, frame: CooSystem) -> &HEALPixCoverage { self.view_hpx_cells.get_cov(frame) } - pub fn get_hpx_cells<'a>( - &'a mut self, - depth: u8, - frame: CooSystem, - ) -> impl Iterator { + pub fn get_hpx_cells(&self, depth: u8, frame: CooSystem) -> Vec { self.view_hpx_cells.get_cells(depth, frame) } @@ -231,12 +231,12 @@ impl CameraViewPort { // check the projection match proj { ProjectionType::Tan(_) => self.aperture >= 100.0_f64.to_radians().to_angle(), - ProjectionType::Mer(_) => self.aperture >= 200.0_f64.to_radians().to_angle(), + ProjectionType::Mer(_) => self.aperture >= 120.0_f64.to_radians().to_angle(), ProjectionType::Stg(_) => self.aperture >= 200.0_f64.to_radians().to_angle(), ProjectionType::Sin(_) => false, - ProjectionType::Ait(_) => false, - ProjectionType::Mol(_) => false, - ProjectionType::Zea(_) => false, + ProjectionType::Ait(_) => self.aperture >= 100.0_f64.to_radians().to_angle(), + ProjectionType::Mol(_) => self.aperture >= 100.0_f64.to_radians().to_angle(), + ProjectionType::Zea(_) => self.aperture >= 140.0_f64.to_radians().to_angle(), } } @@ -679,15 +679,8 @@ use al_core::shader::{SendUniforms, ShaderBound}; impl SendUniforms for CameraViewPort { fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> { shader - //.attach_uniforms_from(&self.last_user_action) - //.attach_uniform("to_icrs", &self.system.to_icrs_j2000::()) - //.attach_uniform("to_galactic", &self.system.to_gal::()) - //.attach_uniform("model", &self.w2m) - //.attach_uniform("inv_model", &self.m2w) .attach_uniform("ndc_to_clip", &self.ndc_to_clip) // Send ndc to clip - .attach_uniform("czf", &self.clip_zoom_factor) // Send clip zoom factor - .attach_uniform("window_size", &self.get_screen_size()) // Window size - .attach_uniform("fov", &self.aperture); + .attach_uniform("czf", &self.clip_zoom_factor); // Send clip zoom factor shader } diff --git a/src/core/src/healpix/cell.rs b/src/core/src/healpix/cell.rs index 1cd94a61..1e31c04a 100644 --- a/src/core/src/healpix/cell.rs +++ b/src/core/src/healpix/cell.rs @@ -14,6 +14,7 @@ use healpix::compass_point::Cardinal; use healpix::compass_point::MainWind; use healpix::compass_point::Ordinal; use healpix::compass_point::OrdinalMap; +use healpix::compass_point::OrdinalSet; use crate::utils; use crate::Abort; diff --git a/src/core/src/renderable/catalog/manager.rs b/src/core/src/renderable/catalog/manager.rs index e21b54e3..9c1b9038 100644 --- a/src/core/src/renderable/catalog/manager.rs +++ b/src/core/src/renderable/catalog/manager.rs @@ -241,10 +241,7 @@ impl Manager { } } else { let depth = camera.get_texture_depth().min(7); - let cells: Vec<_> = camera - .get_hpx_cells(depth, CooSystem::ICRS) - .cloned() - .collect(); + let cells = camera.get_hpx_cells(depth, CooSystem::ICRS); for catalog in self.catalogs.values_mut() { catalog.update(&cells); diff --git a/src/core/src/renderable/coverage/hierarchy.rs b/src/core/src/renderable/coverage/hierarchy.rs index 5d7668de..62c80973 100644 --- a/src/core/src/renderable/coverage/hierarchy.rs +++ b/src/core/src/renderable/coverage/hierarchy.rs @@ -7,16 +7,16 @@ pub struct MOCHierarchy { // MOC at different resolution mocs: Vec, } - +use al_core::WebGlContext; impl MOCHierarchy { - pub fn from_full_res_moc(full_res_moc: HEALPixCoverage, cfg: &Cfg) -> Self { + pub fn from_full_res_moc(gl: WebGlContext, full_res_moc: HEALPixCoverage, cfg: &Cfg) -> Self { let full_res_depth = full_res_moc.depth(); let mut mocs: Vec<_> = (0..full_res_depth) - .map(|d| MOC::new(HEALPixCoverage(full_res_moc.degraded(d)), cfg)) + .map(|d| MOC::new(gl.clone(), HEALPixCoverage(full_res_moc.degraded(d)), cfg)) .collect(); - mocs.push(MOC::new(full_res_moc, cfg)); + mocs.push(MOC::new(gl, full_res_moc, cfg)); Self { mocs, diff --git a/src/core/src/renderable/coverage/moc.rs b/src/core/src/renderable/coverage/moc.rs index a52ff9e2..b6468aaf 100644 --- a/src/core/src/renderable/coverage/moc.rs +++ b/src/core/src/renderable/coverage/moc.rs @@ -1,11 +1,18 @@ +use core::num; + use crate::camera::CameraViewPort; use crate::coo_space::CooSpace; use crate::healpix::cell::CellVertices; use crate::healpix::coverage::HEALPixCoverage; use crate::math::projection::ProjectionType; +use crate::renderable::WebGl2RenderingContext; +use crate::shader::ShaderManager; use al_api::moc::MOC as Cfg; use crate::renderable::coverage::Angle; +use crate::WebGlContext; +use al_core::SliceData; +use al_core::VertexArrayObject; use crate::renderable::line::PathVertices; use crate::renderable::line::RasterizedLineRenderer; @@ -20,6 +27,7 @@ use moclib::moc::RangeMOCIterator; use crate::HEALPixCell; use cgmath::Vector2; +use al_core::VecData; use healpix::compass_point::OrdinalMap; pub struct MOC { @@ -32,17 +40,20 @@ pub struct MOC { } impl MOC { - pub(super) fn new(moc: HEALPixCoverage, cfg: &Cfg) -> Self { + pub(super) fn new(gl: WebGlContext, moc: HEALPixCoverage, cfg: &Cfg) -> Self { let sky_fraction = moc.sky_fraction() as f32; let max_order = moc.depth_max(); let inner = [ if cfg.perimeter { // draw only perimeter - Some(MOCIntern::new(RenderModeType::Perimeter { - thickness: cfg.line_width, - color: cfg.color, - })) + Some(MOCIntern::new( + gl.clone(), + RenderModeType::Perimeter { + thickness: cfg.line_width, + color: cfg.color, + }, + )) } else { None }, @@ -50,15 +61,21 @@ impl MOC { // change color let fill_color = cfg.fill_color; // draw the edges - Some(MOCIntern::new(RenderModeType::Filled { color: fill_color })) + Some(MOCIntern::new( + gl.clone(), + RenderModeType::Filled { color: fill_color }, + )) } else { None }, if cfg.edges { - Some(MOCIntern::new(RenderModeType::Edge { - thickness: cfg.line_width, - color: cfg.color, - })) + Some(MOCIntern::new( + gl, + RenderModeType::Edge { + thickness: cfg.line_width, + color: cfg.color, + }, + )) } else { None }, @@ -108,23 +125,14 @@ impl MOC { } pub(super) fn draw( - &self, + &mut self, camera: &mut CameraViewPort, proj: &ProjectionType, - rasterizer: &mut RasterizedLineRenderer, + shaders: &mut ShaderManager, ) { - let view_depth = camera.get_texture_depth(); - let view_moc = HEALPixCoverage::from_fixed_hpx_cells( - view_depth, - camera - .get_hpx_cells(view_depth, CooSystem::ICRS) - .map(|c| c.idx()), - None, - ); - - for render in &self.inner { - if let Some(render) = render.as_ref() { - render.draw(&view_moc, &self.moc, camera, proj, rasterizer) + for render in &mut self.inner { + if let Some(render) = render.as_mut() { + render.draw(&self.moc, camera, proj, shaders) } } } @@ -138,6 +146,9 @@ struct MOCIntern { // Node indices in view //indices: Vec>, mode: RenderModeType, + + gl: WebGlContext, + vao: VertexArrayObject, } #[derive(Clone)] @@ -148,7 +159,65 @@ pub enum RenderModeType { } use healpix::compass_point::Ordinal; impl MOCIntern { - fn new(mode: RenderModeType) -> Self { + fn new(gl: WebGlContext, mode: RenderModeType) -> Self { + let lonlat = vec![]; + let vertices = [ + 0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32, + ]; + let indices = [0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16]; + let vao = match mode { + RenderModeType::Perimeter { .. } | RenderModeType::Edge { .. } => { + let mut vao = VertexArrayObject::new(&gl); + vao.bind_for_update() + // Store the cartesian position of the center of the source in the a instanced VBO + .add_instanced_array_buffer( + "lonlat", + 4 * std::mem::size_of::(), + &[2, 2], + &[0, 2 * std::mem::size_of::()], + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&lonlat), + ) + .add_array_buffer( + "vertices", + 2 * std::mem::size_of::(), + &[2], + &[0], + WebGl2RenderingContext::STATIC_DRAW, + SliceData(&vertices), + ) + // Set the element buffer + .add_element_buffer(WebGl2RenderingContext::STATIC_DRAW, SliceData(&indices)) + // Unbind the buffer + .unbind(); + + vao + } + RenderModeType::Filled { .. } => { + let mut vao = VertexArrayObject::new(&gl); + let indices = vec![]; + vao.bind_for_update() + // Store the cartesian position of the center of the source in the a instanced VBO + .add_array_buffer( + "lonlat", + 2 * std::mem::size_of::(), + &[2], + &[0], + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&lonlat), + ) + // Set the element buffer + .add_element_buffer( + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&indices), + ) + // Unbind the buffer + .unbind(); + + vao + } + }; + /*let hpx_idx_vec = IdxVec::from_hpx_cells((&moc.0).into_range_moc_iter().cells().flat_map(|cell| { let cell = HEALPixCell(cell.depth, cell.idx); @@ -165,6 +234,8 @@ impl MOCIntern { //moc, //hpx_idx_vec, //indices: vec![], + vao, + gl, mode, } } @@ -271,13 +342,13 @@ impl MOCIntern { fn vertices_in_view<'a>( &self, - view_moc: &'a HEALPixCoverage, moc: &'a HEALPixCoverage, - _camera: &mut CameraViewPort, + camera: &'a mut CameraViewPort, ) -> impl Iterator + 'a { + let view_moc = camera.get_cov(CooSystem::ICRS); //self.cells_in_view(camera) // .filter_map(move |node| node.vertices.as_ref()) - moc.overlapped_by_iter(&view_moc) + moc.overlapped_by_iter(view_moc) .cells() .flat_map(|cell| { let Cell { idx, depth } = cell; @@ -290,46 +361,217 @@ impl MOCIntern { cell.get_tile_cells(dd) }) .map(|hpx_cell| hpx_cell.vertices()) - - //.map(|Cell { idx, depth }| HEALPixCell(depth, idx).vertices()) } fn draw( - &self, - view_moc: &HEALPixCoverage, + &mut self, moc: &HEALPixCoverage, camera: &mut CameraViewPort, proj: &ProjectionType, - rasterizer: &mut RasterizedLineRenderer, + shaders: &mut ShaderManager, ) { let _ = crate::Time::measure_perf("rasterize moc", move || { match self.mode { RenderModeType::Perimeter { thickness, color } => { - let moc_in_view = - HEALPixCoverage(moc.overlapped_by_iter(view_moc).into_range_moc()); - rasterizer.add_stroke_paths( - self.compute_perimeter_paths_iter(&moc_in_view, view_moc, camera, proj), - thickness, - &color, - &super::line::Style::None, - CooSpace::NDC, + let moc_in_view = moc + .overlapped_by_iter(&camera.get_cov(CooSystem::ICRS)) + .into_range_moc(); + let perimeter_vertices_iter = moc_in_view + .border_elementary_edges() + .filter_map(|CellAndEdges { uniq, edges }| { + if edges.is_empty() { + None + } else { + let mut paths = vec![]; + + let c = Cell::from_uniq_hpx(uniq); + let cell = HEALPixCell(c.depth, c.idx); + let v = cell.vertices(); + + if edges.get(moclib::moc::range::Ordinal::SE) { + paths.extend([ + v[0].0 as f32, + v[0].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::NE) { + paths.extend([ + v[1].0 as f32, + v[1].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::NW) { + paths.extend([ + v[2].0 as f32, + v[2].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::SW) { + paths.extend([ + v[3].0 as f32, + v[3].1 as f32, + v[0].0 as f32, + v[0].1 as f32, + ]) + } + + Some(paths) + } + }) + .flatten(); + + let mut buf: Vec<_> = vec![]; + buf.extend(perimeter_vertices_iter); + + self.vao.bind_for_update().update_instanced_array( + "lonlat", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&buf), + ); + + let num_instances = buf.len() / 4; + + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_lonlat.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &color) + .attach_uniform("u_width", &thickness) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + num_instances as i32, ); } RenderModeType::Edge { thickness, color } => { - rasterizer.add_stroke_paths( - self.compute_edge_paths_iter(moc, view_moc, camera, proj), + let mut buf: Vec<_> = vec![]; + buf.extend(self.compute_edge_paths_iter(moc, camera)); + //let mut buf = self.compute_edge_paths_iter(moc, camera).collect(); + + self.vao.bind_for_update().update_instanced_array( + "lonlat", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&buf), + ); + + let num_instances = buf.len() / 4; + + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_lonlat.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &color) + .attach_uniform("u_width", &thickness) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + num_instances as i32, + ); + + /*rasterizer.add_stroke_paths( + , thickness, &color, &super::line::Style::None, CooSpace::LonLat, - ); + );*/ } RenderModeType::Filled { color } => { - rasterizer.add_fill_paths( - self.compute_edge_paths_iter(moc, view_moc, camera, proj), - &color, - CooSpace::NDC, - ); + let mut off_idx = 0; + let mut indices: Vec = vec![]; + let vertices = self + .vertices_in_view(moc, camera) + .map(|v| { + let vertices = [ + v[0].0 as f32, + v[0].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + ]; + + indices.extend_from_slice(&[ + off_idx + 1, + off_idx + 0, + off_idx + 3, + off_idx + 1, + off_idx + 3, + off_idx + 2, + ]); + + off_idx += 4; + + vertices + }) + .flatten() + .collect(); + + let num_idx = indices.len() as i32; + + self.vao + .bind_for_update() + .update_array( + "lonlat", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&vertices), + ) + .update_element_array( + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&indices), + ); + + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + self.gl.enable(WebGl2RenderingContext::BLEND); + + crate::shader::get_shader(&self.gl, shaders, "moc_base.vert", "moc_base.frag")? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &color) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_with_i32( + WebGl2RenderingContext::TRIANGLES, + Some(num_idx), + WebGl2RenderingContext::UNSIGNED_INT, + 0, + ); + + self.gl.disable(WebGl2RenderingContext::BLEND); } } Ok(()) @@ -339,22 +581,8 @@ impl MOCIntern { fn compute_edge_paths_iter<'a>( &self, moc: &'a HEALPixCoverage, - view_moc: &'a HEALPixCoverage, camera: &'a mut CameraViewPort, - proj: &'a ProjectionType, - ) -> impl Iterator> + 'a { - let camera_coosys = camera.get_coo_system(); - // Determine if the view may lead to crossing edges/triangles - // This is dependant on the projection used - let crossing_edges_testing = if proj.is_allsky() { - let sky_percent_covered = camera.get_cov(CooSystem::ICRS).sky_fraction(); - //al_core::info!("sky covered: ", sky_percent_covered); - sky_percent_covered > 0.80 - } else { - // The projection is not allsky. - false - }; - + ) -> impl Iterator + 'a { /*self.vertices_in_view(view_moc, moc, camera) .filter_map(move |cell_vertices| { let mut ndc: [[f32; 2]; 5] = @@ -401,99 +629,29 @@ impl MOCIntern { Some(PathVertices { vertices: ndc }) })*/ - self.vertices_in_view(view_moc, moc, camera).map(|v| { - let vertices = [ - [v[0].0 as f32, v[0].1 as f32], - [v[1].0 as f32, v[1].1 as f32], - [v[2].0 as f32, v[2].1 as f32], - [v[3].0 as f32, v[3].1 as f32], - [v[0].0 as f32, v[0].1 as f32], - ]; - - PathVertices { vertices } - }) - } - - fn compute_perimeter_paths_iter<'a>( - &self, - moc: &'a HEALPixCoverage, - _view_moc: &'a HEALPixCoverage, - camera: &'a mut CameraViewPort, - proj: &'a ProjectionType, - ) -> impl Iterator>> + 'a { - let camera_coosys = camera.get_coo_system(); - // Determine if the view may lead to crossing edges/triangles - // This is dependant on the projection used - let crossing_edges_testing = if proj.is_allsky() { - let sky_percent_covered = camera.get_cov(CooSystem::ICRS).sky_fraction(); - //al_core::info!("sky covered: ", sky_percent_covered); - sky_percent_covered > 0.80 - } else { - // The projection is not allsky. - false - }; - - moc.border_elementary_edges() - .filter_map(|CellAndEdges { uniq, edges }| { - let c = Cell::from_uniq_hpx(uniq); - let cell = HEALPixCell(c.depth, c.idx); - - let mut map = OrdinalMap::new(); - if edges.get(moclib::moc::range::Ordinal::SE) { - map.put(Ordinal::SE, 1); - } - if edges.get(moclib::moc::range::Ordinal::SW) { - map.put(Ordinal::SW, 1); - } - if edges.get(moclib::moc::range::Ordinal::NE) { - map.put(Ordinal::NE, 1); - } - if edges.get(moclib::moc::range::Ordinal::NW) { - map.put(Ordinal::NW, 1); - } - - cell.path_along_sides(&map) - }) - .filter_map(move |CellVertices { vertices }| { - let mut ndc = Vec::<[f32; 2]>::with_capacity(vertices.len() * 2); - - for i in 0..vertices.len() { - let line_vertices = &vertices[i]; - - for k in 0..line_vertices.len() { - let (lon, lat) = line_vertices[k]; - - let xyzw = crate::math::lonlat::radec_to_xyzw(Angle(lon), Angle(lat)); - let xyzw = - crate::coosys::apply_coo_system(CooSystem::ICRS, camera_coosys, &xyzw); - - if let Some(p) = proj.model_to_normalized_device_space(&xyzw, camera) { - if ndc.len() > 0 && crossing_edges_testing { - let mag2 = crate::math::vector::dist2( - crate::math::projection::ndc_to_clip_space(&p, camera).as_ref(), - crate::math::projection::ndc_to_clip_space( - &Vector2::new( - ndc[ndc.len() - 1][0] as f64, - ndc[ndc.len() - 1][1] as f64, - ), - camera, - ) - .as_ref(), - ); - //al_core::info!("mag", i, mag2); - if mag2 > 0.1 { - return None; - } - } - - ndc.push([p.x as f32, p.y as f32]); - } else { - return None; - } - } - } - - Some(PathVertices { vertices: ndc }) + self.vertices_in_view(moc, camera) + .map(|v| { + let vertices = [ + v[0].0 as f32, + v[0].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + v[0].0 as f32, + v[0].1 as f32, + ]; + + vertices }) + .flatten() } } diff --git a/src/core/src/renderable/coverage/mod.rs b/src/core/src/renderable/coverage/mod.rs index 6caa2833..0468b01e 100644 --- a/src/core/src/renderable/coverage/mod.rs +++ b/src/core/src/renderable/coverage/mod.rs @@ -9,8 +9,11 @@ pub mod mode; pub mod hierarchy; pub mod moc; +use web_sys::WebGl2RenderingContext; + use crate::renderable::line::RasterizedLineRenderer; +use al_core::{log::console_log, WebGlContext}; use wasm_bindgen::JsValue; use hierarchy::MOCHierarchy; @@ -22,6 +25,7 @@ use al_api::moc::MOC as Cfg; pub struct MOCRenderer { mocs: Vec, cfgs: Vec, + gl: WebGlContext, } /* @@ -165,7 +169,7 @@ use crate::ProjectionType; use super::line; impl MOCRenderer { - pub fn new() -> Result { + pub fn new(gl: &WebGlContext) -> Result { // layout (location = 0) in vec2 ndc_pos; //let vertices = vec![0.0; MAX_NUM_FLOATS_TO_DRAW]; //let indices = vec![0_u16; MAX_NUM_INDICES_TO_DRAW]; @@ -206,7 +210,11 @@ impl MOCRenderer { let mocs = Vec::new(); let cfgs = Vec::new(); - Ok(Self { mocs, cfgs }) + Ok(Self { + gl: gl.clone(), + mocs, + cfgs, + }) } pub fn push_back( @@ -216,7 +224,8 @@ impl MOCRenderer { camera: &mut CameraViewPort, proj: &ProjectionType, ) { - self.mocs.push(MOCHierarchy::from_full_res_moc(moc, &cfg)); + self.mocs + .push(MOCHierarchy::from_full_res_moc(self.gl.clone(), moc, &cfg)); self.cfgs.push(cfg); camera.register_view_frame(CooSystem::ICRS, proj); @@ -256,7 +265,7 @@ impl MOCRenderer { cfg: Cfg, camera: &mut CameraViewPort, projection: &ProjectionType, - line_renderer: &mut RasterizedLineRenderer, + shaders: &mut ShaderManager, ) -> Option { let name = cfg.get_uuid(); @@ -264,7 +273,7 @@ impl MOCRenderer { let old_cfg = self.cfgs[idx].clone(); self.cfgs[idx] = cfg; - self.update(camera, projection, line_renderer); + self.draw(camera, projection, shaders); Some(old_cfg) } else { @@ -273,51 +282,29 @@ impl MOCRenderer { } } - /*pub fn get(&self, cfg: &Cfg) -> Option<&HEALPixCoverage> { - let key = cfg.get_uuid(); - self.mocs.get(key).map(|coverage| coverage.get_full_moc()) - }*/ - - fn update( - &mut self, - camera: &mut CameraViewPort, - proj: &ProjectionType, - line_renderer: &mut RasterizedLineRenderer, - ) { - for (hmoc, cfg) in self.mocs.iter_mut().zip(self.cfgs.iter()) { - if cfg.show { - let moc = hmoc.select_moc_from_view(camera); - moc.draw(camera, proj, line_renderer); - } - } - - /*self.vao.bind_for_update() - .update_array( - "ndc_pos", - WebGl2RenderingContext::DYNAMIC_DRAW, - VecData(&self.position), - ) - .update_element_array( - WebGl2RenderingContext::DYNAMIC_DRAW, - VecData::(&self.indices), - );*/ - } - pub fn is_empty(&self) -> bool { self.cfgs.is_empty() } pub fn draw( &mut self, - _shaders: &mut ShaderManager, camera: &mut CameraViewPort, - projection: &ProjectionType, - line_renderer: &mut RasterizedLineRenderer, + proj: &ProjectionType, + shaders: &mut ShaderManager, ) { if self.is_empty() { return; } - self.update(camera, projection, line_renderer); + self.gl.enable(WebGl2RenderingContext::CULL_FACE); + + for (hmoc, cfg) in self.mocs.iter_mut().zip(self.cfgs.iter()) { + if cfg.show { + let moc = hmoc.select_moc_from_view(camera); + moc.draw(camera, proj, shaders); + } + } + + self.gl.disable(WebGl2RenderingContext::CULL_FACE); } } diff --git a/src/core/src/renderable/hips/mod.rs b/src/core/src/renderable/hips/mod.rs index d96a7610..44db69a3 100644 --- a/src/core/src/renderable/hips/mod.rs +++ b/src/core/src/renderable/hips/mod.rs @@ -2,7 +2,6 @@ pub mod raytracing; mod triangulation; pub mod uv; -use al_api::coo_system::CooSystem; use al_api::hips::ImageExt; use al_api::hips::ImageMetadata; use al_core::colormap::Colormap; @@ -11,6 +10,7 @@ use al_core::image::format::ChannelType; use al_core::image::Image; +use al_core::log::console_log; use al_core::shader::Shader; use al_core::webgl_ctx::GlWrapper; @@ -28,8 +28,8 @@ use crate::{shader::ShaderManager, survey::config::HiPSConfig}; use crate::downloader::request::allsky::Allsky; use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage}; - use crate::math::lonlat::LonLat; +use crate::renderable::utils::index_patch::DefaultPatchIndexIter; use crate::time::Time; use std::collections::HashSet; @@ -49,8 +49,6 @@ use std::fmt::Debug; use wasm_bindgen::JsValue; use web_sys::WebGl2RenderingContext; -use super::utils::index_patch::CCWCheckPatchIndexIter; - const M: f64 = 280.0 * 280.0; const N: f64 = 150.0 * 150.0; const RAP: f64 = 0.7; @@ -101,7 +99,7 @@ fn num_subdivision(cell: &HEALPixCell, camera: &CameraViewPort, projection: &Pro let skewed_factor = (center_to_vertex_dist - smallest_center_to_vertex_dist) / (largest_center_to_vertex_dist - smallest_center_to_vertex_dist); - if is_too_large(cell, camera, projection) || cell.is_on_pole() || skewed_factor > 0.25 { + if skewed_factor > 0.25 || is_too_large(cell, camera, projection) || cell.is_on_pole() { num_sub += 1; } @@ -396,6 +394,9 @@ pub struct HiPS { //min_depth_tile: u8, footprint_moc: Option, + + // A buffer storing the cells in the view + hpx_cells_in_view: Vec, } impl HiPS { @@ -515,6 +516,7 @@ impl HiPS { let gl = gl.clone(); let footprint_moc = None; + let hpx_cells_in_view = vec![]; // request the allsky texture Ok(HiPS { // The image survey texture buffer @@ -533,14 +535,15 @@ impl HiPS { m1, idx_vertices, - //min_depth_tile, + footprint_moc, + hpx_cells_in_view, }) } pub fn look_for_new_tiles<'a>( &'a mut self, - camera: &'a mut CameraViewPort, + camera: &'a CameraViewPort, proj: &ProjectionType, ) -> Option + 'a> { // do not add tiles if the view is already at depth 0 @@ -575,9 +578,9 @@ impl HiPS { // let texture_cell = cell.get_texture_cell(delta_depth); // texture_cell.get_tile_cells(delta_depth) //}) + .into_iter() .flat_map(move |tile_cell| { let tex_cell = tile_cell.get_texture_cell(dd); - //console_log(&format!("{:?}, dd:{:?}", tex_cell, dd)); tex_cell.get_tile_cells(dd) }) .filter(move |tile_cell| { @@ -623,13 +626,43 @@ impl HiPS { pub fn update(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) { let raytracing = camera.is_raytracing(projection); - let vertices_recomputation_needed = - !raytracing && (self.textures.reset_available_tiles() | camera.has_moved()); - if vertices_recomputation_needed { + if raytracing { + return; + } + + // rasterizer mode + let available_tiles = self.textures.reset_available_tiles(); + let new_cells_in_view = self.retrieve_cells_in_camera(camera); + + if new_cells_in_view || available_tiles { + console_log("recompute vertices/buffer"); self.recompute_vertices(camera, projection); } } + // returns a boolean if the view cells has changed with respect to the last frame + pub fn retrieve_cells_in_camera(&mut self, camera: &CameraViewPort) -> bool { + let cfg = self.textures.config(); + // Get the coo system transformation matrix + let hips_frame = cfg.get_frame(); + let depth = camera.get_texture_depth().min(cfg.get_max_depth_texture()); + + let hpx_cells_in_view = camera.get_hpx_cells(depth, hips_frame); + let new_cells = if hpx_cells_in_view.len() != self.hpx_cells_in_view.len() { + true + } else { + !self + .hpx_cells_in_view + .iter() + .zip(hpx_cells_in_view.iter()) + .all(|(&a, &b)| a == b) + }; + + self.hpx_cells_in_view = hpx_cells_in_view; + + new_cells + } + #[inline] pub fn set_moc(&mut self, moc: HEALPixCoverage) { self.footprint_moc = Some(moc); @@ -711,35 +744,29 @@ impl HiPS { let cfg = self.textures.config(); // Get the coo system transformation matrix - let selected_frame = camera.get_coo_system(); let channel = cfg.get_format().get_channel(); - let hips_frame = cfg.get_frame(); // Retrieve the model and inverse model matrix let mut off_indices = 0; - let depth = camera.get_texture_depth().min(cfg.get_max_depth_texture()); - - let view_cells: Vec<_> = camera.get_hpx_cells(depth, hips_frame).cloned().collect(); - - for cell in &view_cells { + for cell in &self.hpx_cells_in_view { // filter textures that are not in the moc let cell = if let Some(moc) = self.footprint_moc.as_ref() { - if moc.intersects_cell(cell) { - Some(cell) + if moc.intersects_cell(&cell) { + Some(&cell) } else { if channel == ChannelType::RGB8U { // Rasterizer does not render tiles that are not in the MOC // This is not a problem for transparency rendered HiPses (FITS or PNG) // but JPEG tiles do have black when no pixels data is found // We therefore must draw in black for the tiles outside the HiPS MOC - Some(cell) + Some(&cell) } else { None } } } else { - Some(cell) + Some(&cell) }; if let Some(cell) = cell { @@ -827,25 +854,20 @@ impl HiPS { let n_vertices_per_segment = n_segments_by_side + 1; - let mut pos = vec![]; + let mut pos = Vec::with_capacity((n_segments_by_side + 1) * 4); let grid_lonlat = healpix::nested::grid(cell.depth(), cell.idx(), n_segments_by_side as u16); - let grid_lonlat_iter = grid_lonlat - .into_iter() - .map(|(lon, lat)| LonLatT::new(Angle(*lon), Angle(*lat))); + let grid_lonlat_iter = grid_lonlat.into_iter(); - for (idx, lonlat) in grid_lonlat_iter.enumerate() { - let lon = lonlat.lon(); - let lat = lonlat.lat(); + for (idx, &(lon, lat)) in grid_lonlat_iter.enumerate() { + //let xyzw = crate::math::lonlat::radec_to_xyzw(lon, lat); + //let xyzw = + // crate::coosys::apply_coo_system(hips_frame, selected_frame, &xyzw); - let xyzw = crate::math::lonlat::radec_to_xyzw(lon, lat); - let xyzw = - crate::coosys::apply_coo_system(hips_frame, selected_frame, &xyzw); - - let ndc = projection - .model_to_normalized_device_space(&xyzw, camera) - .map(|v| [v.x as f32, v.y as f32]); + //let ndc = projection + // .model_to_normalized_device_space(&xyzw, camera) + // .map(|v| [v.x as f32, v.y as f32]); let i: usize = idx / n_vertices_per_segment; let j: usize = idx % n_vertices_per_segment; @@ -876,15 +898,13 @@ impl HiPS { self.m1.push(miss_1); self.time_tile_received.push(start_time); - pos.push(ndc); + pos.push([lon as f32, lat as f32]); } - let patch_indices_iter = CCWCheckPatchIndexIter::new( + let patch_indices_iter = DefaultPatchIndexIter::new( &(0..=n_segments_by_side), &(0..=n_segments_by_side), n_vertices_per_segment, - &pos, - camera, ) .flatten() .map(|indices| { @@ -902,7 +922,7 @@ impl HiPS { // Replace options with an arbitrary vertex let position_iter = pos .into_iter() - .map(|ndc| ndc.unwrap_or([0.0, 0.0])) + //.map(|ndc| ndc.unwrap_or([0.0, 0.0])) .flatten(); self.position.extend(position_iter); } @@ -1036,10 +1056,6 @@ impl HiPS { let hips_frame = hips_cfg.get_frame(); let c = selected_frame.to(hips_frame); - // Retrieve the model and inverse model matrix - let w2v = c * (*camera.get_w2m()); - let v2w = w2v.transpose(); - let raytracing = camera.is_raytracing(proj); let config = self.get_config(); @@ -1060,6 +1076,8 @@ impl HiPS { blend_cfg.enable(&self.gl, || { if raytracing { + let w2v = c * (*camera.get_w2m()); + let shader = get_raytracer_shader(cmap, &self.gl, shaders, &config)?; let shader = shader.bind(&self.gl); @@ -1070,13 +1088,14 @@ impl HiPS { .attach_uniforms_with_params_from(cmap, colormaps) .attach_uniforms_from(color) .attach_uniform("model", &w2v) - .attach_uniform("inv_model", &v2w) .attach_uniform("current_time", &utils::get_current_time()) .attach_uniform("opacity", opacity) .attach_uniforms_from(colormaps); raytracer.draw(&shader); } else { + let v2w = (*camera.get_m2w()) * c.transpose(); + // The rasterizer has a buffer containing: // - The vertices of the HEALPix cells for the most refined survey // - The starting and ending uv for the blending animation @@ -1096,8 +1115,11 @@ impl HiPS { // send the cmap appart from the color config .attach_uniforms_with_params_from(cmap, colormaps) .attach_uniforms_from(color) + .attach_uniforms_from(camera) + .attach_uniform("inv_model", &v2w) .attach_uniform("current_time", &utils::get_current_time()) .attach_uniform("opacity", opacity) + .attach_uniform("u_proj", proj) .attach_uniforms_from(colormaps) .bind_vertex_array_object_ref(&self.vao) .draw_elements_with_i32( diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index ad85d0db..d4f7f006 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -6,7 +6,6 @@ use crate::math::projection::ProjectionType; use crate::shader::ShaderManager; use crate::Abort; use al_api::coo_system::CooSystem; -use al_core::shader::Shader; use al_core::VertexArrayObject; use al_core::WebGlContext; diff --git a/src/core/src/renderable/mod.rs b/src/core/src/renderable/mod.rs index df1b2e64..19723a56 100644 --- a/src/core/src/renderable/mod.rs +++ b/src/core/src/renderable/mod.rs @@ -38,7 +38,6 @@ use crate::{shader::ShaderManager, survey::config::HiPSConfig}; use hips::raytracing::RayTracer; -use std::borrow::Cow; use std::collections::HashMap; use wasm_bindgen::JsValue; diff --git a/src/core/src/renderable/utils/index_patch.rs b/src/core/src/renderable/utils/index_patch.rs index 53a04d93..3fc1243b 100644 --- a/src/core/src/renderable/utils/index_patch.rs +++ b/src/core/src/renderable/utils/index_patch.rs @@ -1,4 +1,3 @@ - use std::ops::RangeInclusive; use super::triangle::Triangle; diff --git a/src/core/src/shader.rs b/src/core/src/shader.rs index aead1993..d462ac48 100644 --- a/src/core/src/shader.rs +++ b/src/core/src/shader.rs @@ -1,4 +1,3 @@ -use al_core::log::console_log; use al_core::shader::Shader; use al_core::WebGlContext; @@ -50,8 +49,7 @@ pub struct FileSrc { use std::collections::hash_map::Entry; use std::collections::HashMap; -use std::fs::File; -use std::io::Read; + impl ShaderManager { pub fn new() -> Result { let src = crate::shaders::get_all(); @@ -116,7 +114,6 @@ impl ShaderManager { Ok(shader) } } -use std::borrow::Cow; pub(crate) fn get_shader<'a>( gl: &WebGlContext, diff --git a/src/glsl/webgl2/hips/rasterizer/raster.vert b/src/glsl/webgl2/hips/rasterizer/raster.vert index ab7c78d8..7b99eaa7 100644 --- a/src/glsl/webgl2/hips/rasterizer/raster.vert +++ b/src/glsl/webgl2/hips/rasterizer/raster.vert @@ -3,7 +3,7 @@ precision highp float; precision mediump int; //layout (location = 0) in vec3 position; -layout (location = 0) in vec2 ndc_pos; +layout (location = 0) in vec2 lonlat; layout (location = 1) in vec3 uv_start; layout (location = 2) in vec3 uv_end; layout (location = 3) in float time_tile_received; @@ -17,10 +17,21 @@ out float m_start; out float m_end; // current time in ms +uniform mat4 inv_model; +uniform vec2 ndc_to_clip; +uniform float czf; uniform float current_time; +#include ../../projection/projection.glsl; + void main() { - gl_Position = vec4(ndc_pos, 0.0, 1.0); + vec3 p_xyz = lonlat2xyz(lonlat); + vec4 p_w = inv_model * vec4(p_xyz, 1.0); + // 3. Process the projection + vec2 p_clip = proj(p_w.xyz); + + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.0, 1.0); frag_uv_start = uv_start; frag_uv_end = uv_end; diff --git a/src/glsl/webgl2/line/base.frag b/src/glsl/webgl2/line/base.frag index 4356da4e..7b0cc971 100644 --- a/src/glsl/webgl2/line/base.frag +++ b/src/glsl/webgl2/line/base.frag @@ -9,7 +9,7 @@ uniform vec4 u_color; void main() { // Multiply vertex color with texture color (in linear space). // Linear color is written and blended in Framebuffer and converted to sRGB later - if (l > 0.025) { + if (l > 0.05) { discard; } else { color = u_color; diff --git a/src/glsl/webgl2/line/inst_lonlat.vert b/src/glsl/webgl2/line/inst_lonlat.vert index e37383c6..9687b972 100644 --- a/src/glsl/webgl2/line/inst_lonlat.vert +++ b/src/glsl/webgl2/line/inst_lonlat.vert @@ -8,51 +8,11 @@ uniform mat4 u_2world; uniform vec2 ndc_to_clip; uniform float czf; uniform float u_width; -uniform int u_proj; out float l; #include ../projection/projection.glsl; -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -vec2 proj(vec3 p) { - if (u_proj == 0) { - /* TAN, Gnomonic projection */ - return w2c_tan(p); - } else if (u_proj == 1) { - /* STG, Stereographic projection */ - return w2c_stg(p); - } else if (u_proj == 2) { - /* SIN, Orthographic */ - return w2c_sin(p); - } else if (u_proj == 3) { - /* ZEA, Equal-area */ - return w2c_zea(p); - } else if (u_proj == 4) { - // Pseudo-cylindrical projections - /* AIT, Aitoff */ - return w2c_ait(p); - } else if (u_proj == 5) { - // MOL, Mollweide */ - return w2c_mol(p); - } else { - // Cylindrical projections - // MER, Mercator */ - return w2c_mer(p); - } -} - void main() { // 1. Convert (lon, lat) into (x, y, z) space coo. vec3 p_a_xyz = lonlat2xyz(p_a_lonlat); @@ -65,8 +25,8 @@ void main() { vec2 p_b_clip = proj(p_b_w.xyz); vec2 da = p_a_clip - p_b_clip; - l = da.x*da.x + da.y*da.y; + vec2 p_a_ndc = p_a_clip / (ndc_to_clip * czf); vec2 p_b_ndc = p_b_clip / (ndc_to_clip * czf); diff --git a/src/glsl/webgl2/moc/base.frag b/src/glsl/webgl2/moc/base.frag new file mode 100644 index 00000000..f2ff4389 --- /dev/null +++ b/src/glsl/webgl2/moc/base.frag @@ -0,0 +1,12 @@ +#version 300 es + +precision lowp float; +out vec4 color; + +uniform vec4 u_color; + +void main() { + // Multiply vertex color with texture color (in linear space). + // Linear color is written and blended in Framebuffer and converted to sRGB later + color = u_color; +} \ No newline at end of file diff --git a/src/glsl/webgl2/moc/base.vert b/src/glsl/webgl2/moc/base.vert new file mode 100644 index 00000000..8b38c455 --- /dev/null +++ b/src/glsl/webgl2/moc/base.vert @@ -0,0 +1,21 @@ +#version 300 es +precision highp float; +layout (location = 0) in vec2 lonlat; + +uniform mat4 u_2world; +uniform vec2 ndc_to_clip; +uniform float czf; + +#include ../projection/projection.glsl; + +void main() { + // 1. Convert (lon, lat) into (x, y, z) space coo. + vec3 p_xyz = lonlat2xyz(lonlat); + // 2. Convert to the world coo system + vec4 p_w = u_2world * vec4(p_xyz, 1.0); + // 3. Process the projection + vec2 p_clip = proj(p_w.xyz); + + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.f, 1.f); +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/hpx.glsl b/src/glsl/webgl2/projection/hpx.glsl index 80a10173..556194d2 100644 --- a/src/glsl/webgl2/projection/hpx.glsl +++ b/src/glsl/webgl2/projection/hpx.glsl @@ -174,4 +174,4 @@ HashDxDy hash_with_dxdy(int depth, vec3 p) { x - float(i), y - float(j) ); -} \ No newline at end of file +} diff --git a/src/glsl/webgl2/projection/projection.glsl b/src/glsl/webgl2/projection/projection.glsl index 469042bd..8357a412 100644 --- a/src/glsl/webgl2/projection/projection.glsl +++ b/src/glsl/webgl2/projection/projection.glsl @@ -8,4 +8,45 @@ const float SQRT_2 = 1.41421356237309504880168872420969808; #include ./tan.glsl; #include ./stg.glsl; #include ./zea.glsl; -#include ./mer.glsl; \ No newline at end of file +#include ./mer.glsl; + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + /* TAN, Gnomonic projection */ + return w2c_tan(p); + } else if (u_proj == 1) { + /* STG, Stereographic projection */ + return w2c_stg(p); + } else if (u_proj == 2) { + /* SIN, Orthographic */ + return w2c_sin(p); + } else if (u_proj == 3) { + /* ZEA, Equal-area */ + return w2c_zea(p); + } else if (u_proj == 4) { + // Pseudo-cylindrical projections + /* AIT, Aitoff */ + return w2c_ait(p); + } else if (u_proj == 5) { + // MOL, Mollweide */ + return w2c_mol(p); + } else { + // Cylindrical projections + // MER, Mercator */ + return w2c_mer(p); + } +} \ No newline at end of file diff --git a/src/glsl/webgl2/projection/sin.glsl b/src/glsl/webgl2/projection/sin.glsl index c21188e2..52cf0278 100644 --- a/src/glsl/webgl2/projection/sin.glsl +++ b/src/glsl/webgl2/projection/sin.glsl @@ -1,4 +1,8 @@ vec2 w2c_sin(vec3 p) { vec2 q = vec2(-p.x, p.y); return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); } \ No newline at end of file diff --git a/src/glsl/webgl2/projection/tan.glsl b/src/glsl/webgl2/projection/tan.glsl index cbc3d13e..77a405a6 100644 --- a/src/glsl/webgl2/projection/tan.glsl +++ b/src/glsl/webgl2/projection/tan.glsl @@ -1,3 +1,4 @@ vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); return vec2(-p.x, p.y) / (p.z*PI); } \ No newline at end of file diff --git a/src/js/MOC.js b/src/js/MOC.js index 46f9e8ae..8d3d516e 100644 --- a/src/js/MOC.js +++ b/src/js/MOC.js @@ -131,6 +131,7 @@ export let MOC = (function() { this.promiseFetchData .then((data) => { + console.log("jjj") if (data instanceof ArrayBuffer) { // from an url const buf = data; @@ -145,8 +146,13 @@ export let MOC = (function() { self.view.wasm.addPolyMOC(self.mocParams, p.ra, p.dec); } else { // json moc + console.log("22") + self.view.wasm.addJSONMoc(self.mocParams, data); } + + console.log("33") + // Add the fetched moc to the rust backend self.ready = true; @@ -154,9 +160,15 @@ export let MOC = (function() { self.successCallback(self) } + console.log("44") + + // Cache the sky fraction self.skyFrac = self.view.wasm.getMOCSkyFraction(this.mocParams); + + console.log("55") + // Add it to the view self.view.mocs.push(self); self.view.allOverlayLayers.push(self); diff --git a/src/js/gui/Box/StackBox.js b/src/js/gui/Box/StackBox.js index e1081afe..a38cabc4 100644 --- a/src/js/gui/Box/StackBox.js +++ b/src/js/gui/Box/StackBox.js @@ -999,7 +999,7 @@ export class OverlayStackBox extends Box { // load the moc let moc = A.MOCFromURL( layer.url + "/Moc.fits", - { lineWidth: 3, name: layer.name }, + { name: layer.name }, () => { self.mocHiPSUrls[layer.url] = moc; From d8cb01ddefd6aa67287533a5d62850f24708bc62 Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 25 Jun 2024 14:32:55 +0200 Subject: [PATCH 05/12] cache the 12 base cell textures --- src/core/src/survey/buffer.rs | 122 ++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 59 deletions(-) diff --git a/src/core/src/survey/buffer.rs b/src/core/src/survey/buffer.rs index 81859f1a..62c83bbe 100644 --- a/src/core/src/survey/buffer.rs +++ b/src/core/src/survey/buffer.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; use std::collections::BinaryHeap; use std::collections::HashMap; - use al_core::image::format::ChannelType; use cgmath::Vector3; @@ -134,7 +133,7 @@ pub struct ImageSurveyTextures { size: usize, pub textures: HashMap, - //pub base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO], + pub base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO], //pub cutoff_values_tile: Rc>>, // Array of 2D textures @@ -169,15 +168,15 @@ fn create_texture_array( impl ImageSurveyTextures { pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result { - let size = config.num_textures(); + let size = config.num_textures() - NUM_HPX_TILES_DEPTH_ZERO; // Ensures there is at least space for the 12 // root textures - debug_assert!(size >= NUM_HPX_TILES_DEPTH_ZERO); + //debug_assert!(size >= NUM_HPX_TILES_DEPTH_ZERO); let heap = HEALPixCellHeap::with_capacity(size); let textures = HashMap::with_capacity(size); - let _now = Time::now(); - /*let base_textures = [ + let now = Time::now(); + let base_textures = [ Texture::new(&HEALPixCell(0, 0), 0, now), Texture::new(&HEALPixCell(0, 1), 1, now), Texture::new(&HEALPixCell(0, 2), 2, now), @@ -190,7 +189,7 @@ impl ImageSurveyTextures { Texture::new(&HEALPixCell(0, 9), 9, now), Texture::new(&HEALPixCell(0, 10), 10, now), Texture::new(&HEALPixCell(0, 11), 11, now), - ];*/ + ]; let channel = config.get_format().get_channel(); let texture_2d_array = match channel { @@ -221,7 +220,7 @@ impl ImageSurveyTextures { size, //num_root_textures_available, textures, - //base_textures, + base_textures, //num_base_textures, texture_2d_array, available_tiles_during_frame, @@ -252,8 +251,8 @@ impl ImageSurveyTextures { ChannelType::R64F => create_texture_array::(gl, &self.config)?, }; - let _now = Time::now(); - /*self.base_textures = [ + let now = Time::now(); + self.base_textures = [ Texture::new(&HEALPixCell(0, 0), 0, now), Texture::new(&HEALPixCell(0, 1), 1, now), Texture::new(&HEALPixCell(0, 2), 2, now), @@ -266,7 +265,7 @@ impl ImageSurveyTextures { Texture::new(&HEALPixCell(0, 9), 9, now), Texture::new(&HEALPixCell(0, 10), 10, now), Texture::new(&HEALPixCell(0, 11), 11, now), - ];*/ + ]; self.heap.clear(); self.textures.clear(); @@ -315,11 +314,12 @@ impl ImageSurveyTextures { time_request: Time, ) -> Result<(), JsValue> { if !self.contains_tile(cell) { + let dd = self.config.delta_depth(); // Get the texture cell in which the tile has to be - let tex_cell = cell.get_texture_cell(self.config.delta_depth()); + let tex_cell = cell.get_texture_cell(dd); - let _tex_cell_is_root = tex_cell.is_root(self.config.delta_depth()); - if !self.textures.contains_key(&tex_cell) { + let tex_cell_is_root = tex_cell.is_root(dd); + if !tex_cell_is_root && !self.textures.contains_key(&tex_cell) { // The texture is not among the essential ones // (i.e. is not a root texture) let texture = if self.is_heap_full() { @@ -346,6 +346,7 @@ impl ImageSurveyTextures { // The heap buffer is not full, let's create a new // texture with an unique idx // The idx is computed based on the current size of the buffer + /*let idx = if tex_cell_is_root { self.num_base_textures += 1; tex_cell.idx() as usize @@ -353,7 +354,8 @@ impl ImageSurveyTextures { //NUM_HPX_TILES_DEPTH_ZERO + (self.heap.len() - self.num_base_textures) self.heap.len() };*/ - let idx = self.heap.len(); + //let idx = NUM_HPX_TILES_DEPTH_ZERO + (self.heap.len() - self.num_base_textures); + let idx = NUM_HPX_TILES_DEPTH_ZERO + self.heap.len(); Texture::new(&tex_cell, idx as i32, time_request) }; @@ -370,14 +372,14 @@ impl ImageSurveyTextures { // We can safely push it // First get the texture - let texture = //if !tex_cell_is_root { + let texture = if !tex_cell_is_root { self.textures .get_mut(&tex_cell) - .expect("the cell has to be in the tile buffer"); - /* } else { + .expect("the cell has to be in the tile buffer") + } else { let HEALPixCell(_, idx) = tex_cell; &mut self.base_textures[idx as usize] - };*/ + }; let missing = image.is_none(); send_to_gpu( @@ -445,22 +447,23 @@ impl ImageSurveyTextures { // For that purpose, we first need to verify that its // texture ancestor exists and then, it it contains the tile pub fn contains_tile(&self, cell: &HEALPixCell) -> bool { - let texture_cell = cell.get_texture_cell(self.config.delta_depth()); + let dd = self.config.delta_depth(); + let texture_cell = cell.get_texture_cell(dd); - //let tex_cell_is_root = texture_cell.is_root(self.config.delta_depth()); - //if tex_cell_is_root { - // let HEALPixCell(_, idx) = texture_cell; - // self.base_textures[idx as usize].contains(cell) - //} else { - if let Some(texture) = self.get(&texture_cell) { - // The texture is present in the buffer - // We must check whether it contains the tile - texture.contains(cell) + let tex_cell_is_root = texture_cell.is_root(dd); + if tex_cell_is_root { + let HEALPixCell(_, idx) = texture_cell; + self.base_textures[idx as usize].contains(cell) } else { - // The texture in which cell should be is not present - false + if let Some(texture) = self.get(&texture_cell) { + // The texture is present in the buffer + // We must check whether it contains the tile + texture.contains(cell) + } else { + // The texture in which cell should be is not present + false + } } - //} } // Update the priority of the texture containing the tile @@ -469,10 +472,11 @@ impl ImageSurveyTextures { debug_assert!(self.contains_tile(cell)); // Get the texture cell in which the tile has to be - let texture_cell = cell.get_texture_cell(self.config.delta_depth()); - //if texture_cell.is_root(self.config().delta_depth()) { - // return; - //} + let dd = self.config.delta_depth(); + let texture_cell = cell.get_texture_cell(dd); + if texture_cell.is_root(dd) { + return; + } let texture = self .textures @@ -552,33 +556,33 @@ impl ImageSurveyTextures { /// Accessors pub fn get(&self, texture_cell: &HEALPixCell) -> Option<&Texture> { - //if texture_cell.is_root(self.config().delta_depth()) { - // let HEALPixCell(_, idx) = texture_cell; - // Some(&self.base_textures[*idx as usize]) - //} else { - self.textures.get(texture_cell) - //} + if texture_cell.is_root(self.config().delta_depth()) { + let HEALPixCell(_, idx) = texture_cell; + Some(&self.base_textures[*idx as usize]) + } else { + self.textures.get(texture_cell) + } } // Get the nearest parent tile found in the CPU buffer pub fn get_nearest_parent(&self, cell: &HEALPixCell) -> Option { let dd = self.config.delta_depth(); - /*if cell.is_root(dd) { + if cell.is_root(dd) { // Root cells are in the buffer by definition - *cell - } else {*/ - let mut parent_cell = cell.parent(); + Some(*cell) + } else { + let mut parent_cell = cell.parent(); - while !self.contains(&parent_cell) && !parent_cell.is_root(dd) { - parent_cell = parent_cell.parent(); - } + while !self.contains(&parent_cell) && !parent_cell.is_root(dd) { + parent_cell = parent_cell.parent(); + } - if self.contains(&parent_cell) { - Some(parent_cell) - } else { - None + if self.contains(&parent_cell) { + Some(parent_cell) + } else { + None + } } - //} } pub fn config(&self) -> &HiPSConfig { @@ -680,14 +684,14 @@ impl SendUniforms for ImageSurveyTextures { for idx in 0..NUM_HPX_TILES_DEPTH_ZERO { let cell = HEALPixCell(0, idx as u64); - if let Some(texture) = self.get(&cell) { - let texture_uniforms = TextureUniforms::new(texture, idx as i32); - shader.attach_uniforms_from(&texture_uniforms); - } else { + let texture = self.get(&cell).unwrap(); + let texture_uniforms = TextureUniforms::new(texture, idx as i32); + shader.attach_uniforms_from(&texture_uniforms); + /*else { let texture = &Texture::new(&cell, idx as i32, Time::now()); let texture_uniforms = TextureUniforms::new(texture, idx as i32); shader.attach_uniforms_from(&texture_uniforms); - } + }*/ } //} From 957f2b24148b31aa78baa975a0ec7e8a2be0e3fd Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 25 Jun 2024 18:11:37 +0200 Subject: [PATCH 06/12] rename coverage -> moc --- src/core/al-core/src/object/buffer_data.rs | 2 +- src/core/src/app.rs | 4 +- src/core/src/camera/view_hpx_cells.rs | 6 +- src/core/src/healpix/cell.rs | 1 - src/core/src/lib.rs | 5 +- src/core/src/math/projection/mod.rs | 4 +- src/core/src/renderable/hips/mod.rs | 2 - .../src/renderable/{coverage => moc}/graph.rs | 0 .../renderable/{coverage => moc}/hierarchy.rs | 2 +- .../{coverage/moc.rs => moc/mod.rs} | 403 +++++++++--------- .../renderable/{coverage => moc}/mode/edge.rs | 0 .../{coverage => moc}/mode/filled.rs | 0 .../renderable/{coverage => moc}/mode/mod.rs | 2 +- .../{coverage => moc}/mode/perimeter.rs | 0 .../{coverage/mod.rs => moc/renderer.rs} | 45 +- src/core/src/renderable/mod.rs | 24 +- src/glsl/webgl2/projection/ait.glsl | 2 +- src/js/MOC.js | 11 - src/js/ProjectionEnum.js | 2 +- src/js/View.js | 42 +- src/js/Zoom.js | 63 +-- 21 files changed, 272 insertions(+), 348 deletions(-) rename src/core/src/renderable/{coverage => moc}/graph.rs (100%) rename src/core/src/renderable/{coverage => moc}/hierarchy.rs (98%) rename src/core/src/renderable/{coverage/moc.rs => moc/mod.rs} (62%) rename src/core/src/renderable/{coverage => moc}/mode/edge.rs (100%) rename src/core/src/renderable/{coverage => moc}/mode/filled.rs (100%) rename src/core/src/renderable/{coverage => moc}/mode/mod.rs (87%) rename src/core/src/renderable/{coverage => moc}/mode/perimeter.rs (100%) rename src/core/src/renderable/{coverage/mod.rs => moc/renderer.rs} (91%) diff --git a/src/core/al-core/src/object/buffer_data.rs b/src/core/al-core/src/object/buffer_data.rs index 18a5068f..552e2a9e 100644 --- a/src/core/al-core/src/object/buffer_data.rs +++ b/src/core/al-core/src/object/buffer_data.rs @@ -51,7 +51,7 @@ where } fn len(&self) -> usize { - self.len() + self.as_ref().len() } fn ptr(&self) -> *const T { diff --git a/src/core/src/app.rs b/src/core/src/app.rs index ebaa40da..a3db425c 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -12,7 +12,7 @@ use crate::{ }, renderable::Layers, renderable::{ - catalog::Manager, coverage::MOCRenderer, line::RasterizedLineRenderer, ImageCfg, Renderer, + catalog::Manager, line::RasterizedLineRenderer, moc::MOCRenderer, ImageCfg, Renderer, }, shader::ShaderManager, tile_fetcher::TileFetcherQueue, @@ -963,7 +963,7 @@ impl App { &self.projection, &mut self.shaders, //&mut self.line_renderer, - ); + )?; self.line_renderer.begin(); //Time::measure_perf("moc draw", || { diff --git a/src/core/src/camera/view_hpx_cells.rs b/src/core/src/camera/view_hpx_cells.rs index 14125ead..4d968a3a 100644 --- a/src/core/src/camera/view_hpx_cells.rs +++ b/src/core/src/camera/view_hpx_cells.rs @@ -1,14 +1,10 @@ -use crate::healpix::cell::HEALPixCell; -use crate::healpix::cell::MAX_HPX_DEPTH; - use crate::camera::XYZWModel; +use crate::healpix::cell::HEALPixCell; use crate::math::projection::*; use crate::HEALPixCoverage; -use std::ops::Range; - use moclib::moc::{range::op::degrade::degrade, RangeMOCIterator}; pub(super) struct ViewHpxCells { diff --git a/src/core/src/healpix/cell.rs b/src/core/src/healpix/cell.rs index 1e31c04a..1cd94a61 100644 --- a/src/core/src/healpix/cell.rs +++ b/src/core/src/healpix/cell.rs @@ -14,7 +14,6 @@ use healpix::compass_point::Cardinal; use healpix::compass_point::MainWind; use healpix::compass_point::Ordinal; use healpix::compass_point::OrdinalMap; -use healpix::compass_point::OrdinalSet; use crate::utils; use crate::Abort; diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 8dacad8b..db3b2fa7 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -16,7 +16,8 @@ //extern crate itertools_num; //extern crate num; //extern crate num_traits; -use crate::time::Time; +//use crate::time::Time; +#[cfg(feature = "dbg")] use std::panic; pub trait Abort { @@ -140,7 +141,6 @@ pub struct WebClient { } use al_api::hips::ImageMetadata; -use al_core::log::console_log; use std::convert::TryInto; #[wasm_bindgen] impl WebClient { @@ -165,7 +165,6 @@ impl WebClient { let gl = WebGlContext::new(aladin_div)?; let shaders = ShaderManager::new().unwrap_abort(); - console_log("jkjk2"); // Event listeners callbacks //let callback_position_changed = js_sys::Function::new_no_args(""); diff --git a/src/core/src/math/projection/mod.rs b/src/core/src/math/projection/mod.rs index 975e06e5..559fd93a 100644 --- a/src/core/src/math/projection/mod.rs +++ b/src/core/src/math/projection/mod.rs @@ -299,14 +299,14 @@ impl ProjectionType { .map(|pos_normalized_device| ndc_to_screen_space(&pos_normalized_device, camera)) } - pub(crate) fn is_allsky(&self) -> bool { + /*pub(crate) fn is_allsky(&self) -> bool { match self { ProjectionType::Sin(_) | ProjectionType::Tan(_) => false, //| ProjectionType::Feye(_) //| ProjectionType::Ncp(_) => false, _ => true, } - } + }*/ pub fn bounds_size_ratio(&self) -> f64 { match self { diff --git a/src/core/src/renderable/hips/mod.rs b/src/core/src/renderable/hips/mod.rs index 44db69a3..8f042e95 100644 --- a/src/core/src/renderable/hips/mod.rs +++ b/src/core/src/renderable/hips/mod.rs @@ -10,7 +10,6 @@ use al_core::image::format::ChannelType; use al_core::image::Image; -use al_core::log::console_log; use al_core::shader::Shader; use al_core::webgl_ctx::GlWrapper; @@ -635,7 +634,6 @@ impl HiPS { let new_cells_in_view = self.retrieve_cells_in_camera(camera); if new_cells_in_view || available_tiles { - console_log("recompute vertices/buffer"); self.recompute_vertices(camera, projection); } } diff --git a/src/core/src/renderable/coverage/graph.rs b/src/core/src/renderable/moc/graph.rs similarity index 100% rename from src/core/src/renderable/coverage/graph.rs rename to src/core/src/renderable/moc/graph.rs diff --git a/src/core/src/renderable/coverage/hierarchy.rs b/src/core/src/renderable/moc/hierarchy.rs similarity index 98% rename from src/core/src/renderable/coverage/hierarchy.rs rename to src/core/src/renderable/moc/hierarchy.rs index 62c80973..e3698cf6 100644 --- a/src/core/src/renderable/coverage/hierarchy.rs +++ b/src/core/src/renderable/moc/hierarchy.rs @@ -1,4 +1,4 @@ -use super::moc::MOC; +use super::MOC; use crate::{camera::CameraViewPort, HEALPixCoverage}; use al_api::moc::MOC as Cfg; diff --git a/src/core/src/renderable/coverage/moc.rs b/src/core/src/renderable/moc/mod.rs similarity index 62% rename from src/core/src/renderable/coverage/moc.rs rename to src/core/src/renderable/moc/mod.rs index b6468aaf..67a78206 100644 --- a/src/core/src/renderable/coverage/moc.rs +++ b/src/core/src/renderable/moc/mod.rs @@ -1,21 +1,22 @@ -use core::num; +mod graph; +mod mode; + +pub mod hierarchy; +pub mod renderer; +pub use renderer::MOCRenderer; use crate::camera::CameraViewPort; -use crate::coo_space::CooSpace; -use crate::healpix::cell::CellVertices; use crate::healpix::coverage::HEALPixCoverage; use crate::math::projection::ProjectionType; use crate::renderable::WebGl2RenderingContext; use crate::shader::ShaderManager; use al_api::moc::MOC as Cfg; -use crate::renderable::coverage::Angle; +use wasm_bindgen::JsValue; + use crate::WebGlContext; -use al_core::SliceData; use al_core::VertexArrayObject; -use crate::renderable::line::PathVertices; -use crate::renderable::line::RasterizedLineRenderer; use al_api::color::ColorRGBA; use al_api::coo_system::CooSystem; @@ -25,10 +26,8 @@ use moclib::moc::range::CellAndEdges; use moclib::moc::RangeMOCIterator; use crate::HEALPixCell; -use cgmath::Vector2; use al_core::VecData; -use healpix::compass_point::OrdinalMap; pub struct MOC { pub sky_fraction: f32, @@ -129,12 +128,14 @@ impl MOC { camera: &mut CameraViewPort, proj: &ProjectionType, shaders: &mut ShaderManager, - ) { + ) -> Result<(), JsValue> { for render in &mut self.inner { if let Some(render) = render.as_mut() { - render.draw(&self.moc, camera, proj, shaders) + render.draw(&self.moc, camera, proj, shaders)? } } + + Ok(()) } } @@ -157,7 +158,6 @@ pub enum RenderModeType { Edge { thickness: f32, color: ColorRGBA }, Filled { color: ColorRGBA }, } -use healpix::compass_point::Ordinal; impl MOCIntern { fn new(gl: WebGlContext, mode: RenderModeType) -> Self { let lonlat = vec![]; @@ -184,10 +184,10 @@ impl MOCIntern { &[2], &[0], WebGl2RenderingContext::STATIC_DRAW, - SliceData(&vertices), + &vertices as &[f32], ) // Set the element buffer - .add_element_buffer(WebGl2RenderingContext::STATIC_DRAW, SliceData(&indices)) + .add_element_buffer(WebGl2RenderingContext::STATIC_DRAW, &indices as &[u16]) // Unbind the buffer .unbind(); @@ -369,213 +369,210 @@ impl MOCIntern { camera: &mut CameraViewPort, proj: &ProjectionType, shaders: &mut ShaderManager, - ) { - let _ = crate::Time::measure_perf("rasterize moc", move || { - match self.mode { - RenderModeType::Perimeter { thickness, color } => { - let moc_in_view = moc - .overlapped_by_iter(&camera.get_cov(CooSystem::ICRS)) - .into_range_moc(); - let perimeter_vertices_iter = moc_in_view - .border_elementary_edges() - .filter_map(|CellAndEdges { uniq, edges }| { - if edges.is_empty() { - None - } else { - let mut paths = vec![]; - - let c = Cell::from_uniq_hpx(uniq); - let cell = HEALPixCell(c.depth, c.idx); - let v = cell.vertices(); - - if edges.get(moclib::moc::range::Ordinal::SE) { - paths.extend([ - v[0].0 as f32, - v[0].1 as f32, - v[1].0 as f32, - v[1].1 as f32, - ]); - } - if edges.get(moclib::moc::range::Ordinal::NE) { - paths.extend([ - v[1].0 as f32, - v[1].1 as f32, - v[2].0 as f32, - v[2].1 as f32, - ]); - } - if edges.get(moclib::moc::range::Ordinal::NW) { - paths.extend([ - v[2].0 as f32, - v[2].1 as f32, - v[3].0 as f32, - v[3].1 as f32, - ]); - } - if edges.get(moclib::moc::range::Ordinal::SW) { - paths.extend([ - v[3].0 as f32, - v[3].1 as f32, - v[0].0 as f32, - v[0].1 as f32, - ]) - } - - Some(paths) + ) -> Result<(), JsValue> { + //let _ = crate::Time::measure_perf("rasterize moc", move || { + match self.mode { + RenderModeType::Perimeter { thickness, color } => { + let moc_in_view = moc + .overlapped_by_iter(&camera.get_cov(CooSystem::ICRS)) + .into_range_moc(); + let perimeter_vertices_iter = moc_in_view + .border_elementary_edges() + .filter_map(|CellAndEdges { uniq, edges }| { + if edges.is_empty() { + None + } else { + let mut paths = vec![]; + + let c = Cell::from_uniq_hpx(uniq); + let cell = HEALPixCell(c.depth, c.idx); + let v = cell.vertices(); + + if edges.get(moclib::moc::range::Ordinal::SE) { + paths.extend([ + v[0].0 as f32, + v[0].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::NE) { + paths.extend([ + v[1].0 as f32, + v[1].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::NW) { + paths.extend([ + v[2].0 as f32, + v[2].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + ]); + } + if edges.get(moclib::moc::range::Ordinal::SW) { + paths.extend([ + v[3].0 as f32, + v[3].1 as f32, + v[0].0 as f32, + v[0].1 as f32, + ]) } - }) - .flatten(); - - let mut buf: Vec<_> = vec![]; - buf.extend(perimeter_vertices_iter); - - self.vao.bind_for_update().update_instanced_array( - "lonlat", - WebGl2RenderingContext::DYNAMIC_DRAW, - VecData::(&buf), - ); - - let num_instances = buf.len() / 4; - - let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); - let view2world = camera.get_m2w(); - let icrs2world = view2world * icrs2view; - - crate::shader::get_shader( - &self.gl, - shaders, - "line_inst_lonlat.vert", - "line_base.frag", - )? - .bind(&self.gl) - .attach_uniforms_from(camera) - .attach_uniform("u_2world", &icrs2world) - .attach_uniform("u_color", &color) - .attach_uniform("u_width", &thickness) - .attach_uniform("u_proj", proj) - .bind_vertex_array_object_ref(&self.vao) - .draw_elements_instanced_with_i32( - WebGl2RenderingContext::TRIANGLES, - 0, - num_instances as i32, - ); - } - RenderModeType::Edge { thickness, color } => { - let mut buf: Vec<_> = vec![]; - buf.extend(self.compute_edge_paths_iter(moc, camera)); - //let mut buf = self.compute_edge_paths_iter(moc, camera).collect(); - self.vao.bind_for_update().update_instanced_array( + Some(paths) + } + }) + .flatten(); + + let mut buf: Vec<_> = vec![]; + buf.extend(perimeter_vertices_iter); + + self.vao.bind_for_update().update_instanced_array( + "lonlat", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&buf), + ); + + let num_instances = buf.len() / 4; + + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_lonlat.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &color) + .attach_uniform("u_width", &thickness) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + num_instances as i32, + ); + } + RenderModeType::Edge { thickness, color } => { + let mut buf: Vec<_> = vec![]; + buf.extend(self.compute_edge_paths_iter(moc, camera)); + //let mut buf = self.compute_edge_paths_iter(moc, camera).collect(); + + self.vao.bind_for_update().update_instanced_array( + "lonlat", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData::(&buf), + ); + + let num_instances = buf.len() / 4; + + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; + + crate::shader::get_shader( + &self.gl, + shaders, + "line_inst_lonlat.vert", + "line_base.frag", + )? + .bind(&self.gl) + .attach_uniforms_from(camera) + .attach_uniform("u_2world", &icrs2world) + .attach_uniform("u_color", &color) + .attach_uniform("u_width", &thickness) + .attach_uniform("u_proj", proj) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + num_instances as i32, + ); + + /*rasterizer.add_stroke_paths( + , + thickness, + &color, + &super::line::Style::None, + CooSpace::LonLat, + );*/ + } + RenderModeType::Filled { color } => { + let mut off_idx = 0; + let mut indices: Vec = vec![]; + let vertices = self + .vertices_in_view(moc, camera) + .map(|v| { + let vertices = [ + v[0].0 as f32, + v[0].1 as f32, + v[1].0 as f32, + v[1].1 as f32, + v[2].0 as f32, + v[2].1 as f32, + v[3].0 as f32, + v[3].1 as f32, + ]; + + indices.extend_from_slice(&[ + off_idx + 1, + off_idx + 0, + off_idx + 3, + off_idx + 1, + off_idx + 3, + off_idx + 2, + ]); + + off_idx += 4; + + vertices + }) + .flatten() + .collect(); + + let num_idx = indices.len() as i32; + + self.vao + .bind_for_update() + .update_array( "lonlat", WebGl2RenderingContext::DYNAMIC_DRAW, - VecData::(&buf), - ); + VecData(&vertices), + ) + .update_element_array(WebGl2RenderingContext::DYNAMIC_DRAW, VecData(&indices)); - let num_instances = buf.len() / 4; + let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); + let view2world = camera.get_m2w(); + let icrs2world = view2world * icrs2view; - let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); - let view2world = camera.get_m2w(); - let icrs2world = view2world * icrs2view; + self.gl.enable(WebGl2RenderingContext::BLEND); - crate::shader::get_shader( - &self.gl, - shaders, - "line_inst_lonlat.vert", - "line_base.frag", - )? + crate::shader::get_shader(&self.gl, shaders, "moc_base.vert", "moc_base.frag")? .bind(&self.gl) .attach_uniforms_from(camera) .attach_uniform("u_2world", &icrs2world) .attach_uniform("u_color", &color) - .attach_uniform("u_width", &thickness) .attach_uniform("u_proj", proj) .bind_vertex_array_object_ref(&self.vao) - .draw_elements_instanced_with_i32( + .draw_elements_with_i32( WebGl2RenderingContext::TRIANGLES, + Some(num_idx), + WebGl2RenderingContext::UNSIGNED_INT, 0, - num_instances as i32, ); - /*rasterizer.add_stroke_paths( - , - thickness, - &color, - &super::line::Style::None, - CooSpace::LonLat, - );*/ - } - RenderModeType::Filled { color } => { - let mut off_idx = 0; - let mut indices: Vec = vec![]; - let vertices = self - .vertices_in_view(moc, camera) - .map(|v| { - let vertices = [ - v[0].0 as f32, - v[0].1 as f32, - v[1].0 as f32, - v[1].1 as f32, - v[2].0 as f32, - v[2].1 as f32, - v[3].0 as f32, - v[3].1 as f32, - ]; - - indices.extend_from_slice(&[ - off_idx + 1, - off_idx + 0, - off_idx + 3, - off_idx + 1, - off_idx + 3, - off_idx + 2, - ]); - - off_idx += 4; - - vertices - }) - .flatten() - .collect(); - - let num_idx = indices.len() as i32; - - self.vao - .bind_for_update() - .update_array( - "lonlat", - WebGl2RenderingContext::DYNAMIC_DRAW, - VecData(&vertices), - ) - .update_element_array( - WebGl2RenderingContext::DYNAMIC_DRAW, - VecData(&indices), - ); - - let icrs2view = CooSystem::ICRS.to(camera.get_coo_system()); - let view2world = camera.get_m2w(); - let icrs2world = view2world * icrs2view; - - self.gl.enable(WebGl2RenderingContext::BLEND); - - crate::shader::get_shader(&self.gl, shaders, "moc_base.vert", "moc_base.frag")? - .bind(&self.gl) - .attach_uniforms_from(camera) - .attach_uniform("u_2world", &icrs2world) - .attach_uniform("u_color", &color) - .attach_uniform("u_proj", proj) - .bind_vertex_array_object_ref(&self.vao) - .draw_elements_with_i32( - WebGl2RenderingContext::TRIANGLES, - Some(num_idx), - WebGl2RenderingContext::UNSIGNED_INT, - 0, - ); - - self.gl.disable(WebGl2RenderingContext::BLEND); - } + self.gl.disable(WebGl2RenderingContext::BLEND); } - Ok(()) - }); + } + Ok(()) + //}); } fn compute_edge_paths_iter<'a>( diff --git a/src/core/src/renderable/coverage/mode/edge.rs b/src/core/src/renderable/moc/mode/edge.rs similarity index 100% rename from src/core/src/renderable/coverage/mode/edge.rs rename to src/core/src/renderable/moc/mode/edge.rs diff --git a/src/core/src/renderable/coverage/mode/filled.rs b/src/core/src/renderable/moc/mode/filled.rs similarity index 100% rename from src/core/src/renderable/coverage/mode/filled.rs rename to src/core/src/renderable/moc/mode/filled.rs diff --git a/src/core/src/renderable/coverage/mode/mod.rs b/src/core/src/renderable/moc/mode/mod.rs similarity index 87% rename from src/core/src/renderable/coverage/mode/mod.rs rename to src/core/src/renderable/moc/mode/mod.rs index fdd11db5..4cbed358 100644 --- a/src/core/src/renderable/coverage/mode/mod.rs +++ b/src/core/src/renderable/moc/mode/mod.rs @@ -1,5 +1,5 @@ use crate::healpix::cell::CellVertices; -use crate::renderable::coverage::HEALPixCell; +use crate::HEALPixCell; use crate::HEALPixCoverage; pub mod edge; diff --git a/src/core/src/renderable/coverage/mode/perimeter.rs b/src/core/src/renderable/moc/mode/perimeter.rs similarity index 100% rename from src/core/src/renderable/coverage/mode/perimeter.rs rename to src/core/src/renderable/moc/mode/perimeter.rs diff --git a/src/core/src/renderable/coverage/mod.rs b/src/core/src/renderable/moc/renderer.rs similarity index 91% rename from src/core/src/renderable/coverage/mod.rs rename to src/core/src/renderable/moc/renderer.rs index 0468b01e..f8b25f71 100644 --- a/src/core/src/renderable/coverage/mod.rs +++ b/src/core/src/renderable/moc/renderer.rs @@ -1,22 +1,10 @@ -use crate::{ - healpix::{cell::HEALPixCell, coverage::HEALPixCoverage}, - math::angle::Angle, - CameraViewPort, ShaderManager, -}; -mod graph; -pub mod mode; - -pub mod hierarchy; -pub mod moc; - +use crate::{healpix::coverage::HEALPixCoverage, CameraViewPort, ShaderManager}; use web_sys::WebGl2RenderingContext; -use crate::renderable::line::RasterizedLineRenderer; - -use al_core::{log::console_log, WebGlContext}; +use al_core::WebGlContext; use wasm_bindgen::JsValue; -use hierarchy::MOCHierarchy; +use super::hierarchy::MOCHierarchy; use al_api::coo_system::CooSystem; @@ -167,7 +155,6 @@ fn rasterize_hpx_cell( use crate::ProjectionType; -use super::line; impl MOCRenderer { pub fn new(gl: &WebGlContext) -> Result { // layout (location = 0) in vec2 ndc_pos; @@ -273,7 +260,7 @@ impl MOCRenderer { let old_cfg = self.cfgs[idx].clone(); self.cfgs[idx] = cfg; - self.draw(camera, projection, shaders); + let _ = self.draw(camera, projection, shaders); Some(old_cfg) } else { @@ -291,20 +278,20 @@ impl MOCRenderer { camera: &mut CameraViewPort, proj: &ProjectionType, shaders: &mut ShaderManager, - ) { - if self.is_empty() { - return; - } - - self.gl.enable(WebGl2RenderingContext::CULL_FACE); - - for (hmoc, cfg) in self.mocs.iter_mut().zip(self.cfgs.iter()) { - if cfg.show { - let moc = hmoc.select_moc_from_view(camera); - moc.draw(camera, proj, shaders); + ) -> Result<(), JsValue> { + if !self.is_empty() { + self.gl.enable(WebGl2RenderingContext::CULL_FACE); + + for (hmoc, cfg) in self.mocs.iter_mut().zip(self.cfgs.iter()) { + if cfg.show { + let moc = hmoc.select_moc_from_view(camera); + moc.draw(camera, proj, shaders)?; + } } + + self.gl.disable(WebGl2RenderingContext::CULL_FACE); } - self.gl.disable(WebGl2RenderingContext::CULL_FACE); + Ok(()) } } diff --git a/src/core/src/renderable/mod.rs b/src/core/src/renderable/mod.rs index 19723a56..d76c16b2 100644 --- a/src/core/src/renderable/mod.rs +++ b/src/core/src/renderable/mod.rs @@ -1,9 +1,9 @@ pub mod catalog; -pub mod coverage; pub mod final_pass; pub mod hips; pub mod image; pub mod line; +pub mod moc; pub mod text; pub mod utils; @@ -23,7 +23,6 @@ use al_api::image::ImageParams; use al_core::colormap::Colormaps; use al_core::shader::Shader; -use al_core::SliceData; use al_core::VertexArrayObject; use al_core::WebGlContext; @@ -138,29 +137,12 @@ impl Layers { 2, "pos_clip_space", WebGl2RenderingContext::STATIC_DRAW, - SliceData::(&[-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0]), + &[-1.0_f32, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0] as &[f32], ) // Set the element buffer .add_element_buffer( WebGl2RenderingContext::STATIC_DRAW, - SliceData::(&[0, 1, 2, 0, 2, 3]), - ) - // Unbind the buffer - .unbind(); - - #[cfg(feature = "webgl1")] - screen_vao - .bind_for_update() - .add_array_buffer( - 2, - "pos_clip_space", - WebGl2RenderingContext::STATIC_DRAW, - SliceData::(&[-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0]), - ) - // Set the element buffer - .add_element_buffer( - WebGl2RenderingContext::STATIC_DRAW, - SliceData::(&[0, 1, 2, 0, 2, 3]), + &[0_u16, 1, 2, 0, 2, 3] as &[u16], ) // Unbind the buffer .unbind(); diff --git a/src/glsl/webgl2/projection/ait.glsl b/src/glsl/webgl2/projection/ait.glsl index 8b18713d..b9494bd6 100644 --- a/src/glsl/webgl2/projection/ait.glsl +++ b/src/glsl/webgl2/projection/ait.glsl @@ -6,7 +6,7 @@ vec2 w2c_ait(vec3 p) { float y2d = p.y / w; float x2d = 0.0; - if (abs(p.x) < 1e-3) { + if (abs(p.x) < 5e-3) { float x_over_r = p.x/r; x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; } else { diff --git a/src/js/MOC.js b/src/js/MOC.js index 8d3d516e..15e6ceeb 100644 --- a/src/js/MOC.js +++ b/src/js/MOC.js @@ -131,7 +131,6 @@ export let MOC = (function() { this.promiseFetchData .then((data) => { - console.log("jjj") if (data instanceof ArrayBuffer) { // from an url const buf = data; @@ -146,13 +145,9 @@ export let MOC = (function() { self.view.wasm.addPolyMOC(self.mocParams, p.ra, p.dec); } else { // json moc - console.log("22") - self.view.wasm.addJSONMoc(self.mocParams, data); } - console.log("33") - // Add the fetched moc to the rust backend self.ready = true; @@ -160,15 +155,9 @@ export let MOC = (function() { self.successCallback(self) } - console.log("44") - - // Cache the sky fraction self.skyFrac = self.view.wasm.getMOCSkyFraction(this.mocParams); - - console.log("55") - // Add it to the view self.view.mocs.push(self); self.view.allOverlayLayers.push(self); diff --git a/src/js/ProjectionEnum.js b/src/js/ProjectionEnum.js index a5b1c34f..a8e2760b 100644 --- a/src/js/ProjectionEnum.js +++ b/src/js/ProjectionEnum.js @@ -30,7 +30,7 @@ export let ProjectionEnum = { // Zenithal TAN: {id: 1, fov: 150, label: "Tangential"}, /* Gnomonic projection */ - STG: {id: 2, fov: 360, label: "Stereographic"}, /* Stereographic projection */ + STG: {id: 2, fov: 240, label: "Stereographic"}, /* Stereographic projection */ SIN: {id: 3, fov: 180, label: "Spheric"}, /* Orthographic */ // TODO: fix why the projection disappears at fov = 360.0 ZEA: {id: 4, fov: 359.999, label: "Zenital equal-area"}, /* Equal-area */ diff --git a/src/js/View.js b/src/js/View.js index 7f1bbfee..6993faa7 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -36,9 +36,6 @@ import { ProjectionEnum } from "./ProjectionEnum.js"; import { Utils } from "./Utils"; import { GenericPointer } from "./GenericPointer.js"; import { Stats } from "./libs/Stats.js"; -import { Circle } from "./shapes/Circle.js"; -import { Ellipse } from "./shapes/Ellipse.js"; -import { Polyline } from "./shapes/Polyline.js"; import { CooFrameEnum } from "./CooFrameEnum.js"; import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; import { WebGLCtx } from "./WebGL.js"; @@ -1127,8 +1124,10 @@ export let View = (function () { clearTimeout(id); id = setTimeout(() => { view.wheelTriggered = false; + view.zoom.stopAnimation(); }, 100); + const xymouse = Utils.relMouseCoords(e); view.xy = xymouse ALEvent.CANVAS_EVENT.dispatchedTo(view.aladinDiv, { @@ -1189,24 +1188,35 @@ export let View = (function () { if (isTouchPad) { if (!view.throttledTouchPadZoom) { - let radec; + //let radec; view.throttledTouchPadZoom = Utils.throttle(() => { - if (!view.zoom.isZooming && !view.wheelTriggered) { + /*if (!view.zoom.isZooming && !view.wheelTriggered) { // start zooming detected radec = view.aladin.pix2world(view.xy.x, view.xy.y); - } - - let amount = view.delta > 0 ? -Zoom.MAX_IDX_DELTA_PER_TROTTLE : Zoom.MAX_IDX_DELTA_PER_TROTTLE; - if (amount === 0) - return; + }*/ - // change the zoom level - let newFov = Zoom.determineNextFov(view, amount); + const factor = 4; + let newFov = view.delta > 0 ? view.fov * factor : view.fov / factor; + + // standard mouse wheel zooming + newFov = Math.min(newFov, view.projection.fov); + + // then clamp the fov between minFov and maxFov + const minFoV = view.minFoV; + const maxFoV = view.maxFoV; + + if (minFoV) { + fov = Math.max(fov, minFoV); + } + + if (maxFoV) { + fov = Math.min(fov, maxFoV); + } + view.zoom.apply({ stop: newFov, duration: 300 }); - //view.setZoom(newFov) /*if (amount > 0 && radec) { let sRaDec = view.aladin.getRaDec(); @@ -1224,7 +1234,7 @@ export let View = (function () { } //requestAnimFrame(moveTo) }*/ - }, 40); + }, 100); } view.throttledTouchPadZoom(); @@ -1241,7 +1251,7 @@ export let View = (function () { stop: newFov, duration: 300 }); - }, 30); + }, 50); } view.throttledMouseScrollZoom() @@ -1599,7 +1609,7 @@ export let View = (function () { fovX = Math.min(fovX, 360); fovY = Math.min(fovY, 180); - ALEvent.ZOOM_CHANGED.dispatchedTo(this.aladinDiv, { fovX: fovX, fovY: fovY }); + ALEvent.ZOOM_CHANGED.dispatchedTo(this.aladinDiv, { fovX, fovY }); this.throttledZoomChanged(); }; diff --git a/src/js/Zoom.js b/src/js/Zoom.js index 57aaad3b..b0504a09 100644 --- a/src/js/Zoom.js +++ b/src/js/Zoom.js @@ -36,47 +36,6 @@ import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; function Zoom(view) { this.view = view; }; - - Zoom.LEVELS = [ - 360, 330, 300, 275, 250, 225, 200, 190, - 180, 170, 160, 150, 140, 130, 120, 110, 100, - 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 18, 16, 14, 12, 10, - 9, 8, 7, 6, 5, 4, 3, 2, 1.75, 1.5, 1.25, 1, - 55/60, 50/60, 45/60, 40/60, 35/60, 30/60, 25/60, 20/60, 15/60, 10/60, - 9/60, 8/60, 7/60, 6/60, 5/60, 4/60, 3/60, 2/60, 1/60, - 50/3600, 40/3600, 30/3600, 20/3600, 10/3600, - 9/3600, 8/3600, 7/3600, 6/3600, 5/3600, 4/3600, 3/3600, 2/3600, 1/3600, - 9/36000, 8/36000, 7/36000, 6/36000, 5/36000, 4/36000, 3/36000, 2/36000, 1/36000 - ]; - Zoom.MAX_IDX_DELTA_PER_TROTTLE = 6; - - Zoom.determineNextFov = function(view, amount) { - const currIdx = Utils.binarySearch(Zoom.LEVELS, view.fov); - - let deltaIdx = amount; - let nextIdx = currIdx + deltaIdx; - - // clamp to the array indices - if (nextIdx < 0) { - nextIdx = 0 - } - - if (nextIdx >= Zoom.LEVELS.length) { - nextIdx = Zoom.LEVELS.length - 1 - } - - let nextFov = Zoom.LEVELS[nextIdx]; - - if (view.minFoV) { - nextFov = Math.max(nextFov, view.minFoV) - } - - if (view.maxFoV) { - nextFov = Math.min(nextFov, view.maxFoV) - } - - return nextFov; - } Zoom.prototype.apply = function(options) { let startZoom = options['start'] || this.view.fov; @@ -112,6 +71,9 @@ import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; this.y2 = finalZoom; this.m1 = m1; this.m2 = 0; + + // we must delete the current request anim frame + window.cancelAnimationFrame(this.requestAnimID) } // Initialize current zoom to the current zoom level @@ -119,7 +81,6 @@ import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; let self = this; // Recursive function to perform interpolation for each frame function interpolateFrame() { - //console.log('zooming') //fps = 1000 / self.dt; //totalFrames = interpolationDuration * fps; // Total number of frames self.x = ( performance.now() - self.startTime ) / interpolationDuration; @@ -127,7 +88,7 @@ import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; //stepSize = (desiredZoom - currentZoom) / totalFrames; interpolatedZoom = Zoom.hermiteCubic.f(self.x, self.x1, self.x2, self.y1, self.y2, self.m1, self.m2); // Clamp the interpolation in case it is < 0 for a time - interpolatedZoom = Math.max(Zoom.MIN, interpolatedZoom); + interpolatedZoom = Math.max(0, interpolatedZoom); // Apply zoom level to map or perform any necessary rendering self.view.setZoom(interpolatedZoom); @@ -135,22 +96,28 @@ import { requestAnimFrame } from "./libs/RequestAnimationFrame.js"; self.fov = interpolatedZoom; // Check if interpolation is complete - if (self.x >= self.x2 || Math.abs(interpolatedZoom - self.finalZoom) < 1e-4) { + if (self.stop) { + self.isZooming = false; + self.stop = false; + } else if (self.x >= self.x2 || Math.abs(interpolatedZoom - self.finalZoom) < 1e-4) { self.view.setZoom(self.finalZoom); self.isZooming = false; } else { // Request the next frame - requestAnimFrame(interpolateFrame); + self.requestAnimID = requestAnimFrame(interpolateFrame); } } // Start interpolation by requesting the first frame - requestAnimFrame(interpolateFrame); + self.requestAnimID = requestAnimFrame(interpolateFrame); } - Zoom.MAX = Zoom.LEVELS[0]; - Zoom.MIN = Zoom.LEVELS[Zoom.LEVELS.length - 1]; + Zoom.prototype.stopAnimation = function() { + if (this.isZooming) { + this.stop = true; + } + } Zoom.hermiteCubic = { f: function(x, x1, x2, y1, y2, m1, m2) { From 2b69ae8a0d101b323337629ae8b1d4cfb0fe6e7d Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Wed, 26 Jun 2024 11:02:37 +0200 Subject: [PATCH 07/12] move grid rendering from line rasterizer to grid module --- src/core/src/app.rs | 6 +- src/core/src/image/fits.rs | 0 src/core/src/image/jpg.rs | 0 src/core/src/image/mod.rs | 2 - src/core/src/lib.rs | 1 - src/core/src/{ => renderable}/grid/label.rs | 2 +- .../src/{ => renderable}/grid/meridian.rs | 2 +- src/core/src/{ => renderable}/grid/mod.rs | 250 ++++++++++-------- .../src/{ => renderable}/grid/parallel.rs | 0 src/core/src/renderable/line/mod.rs | 8 +- src/core/src/renderable/mod.rs | 1 + src/js/View.js | 7 +- 12 files changed, 161 insertions(+), 118 deletions(-) delete mode 100644 src/core/src/image/fits.rs delete mode 100644 src/core/src/image/jpg.rs delete mode 100644 src/core/src/image/mod.rs rename src/core/src/{ => renderable}/grid/label.rs (98%) rename src/core/src/{ => renderable}/grid/meridian.rs (99%) rename src/core/src/{ => renderable}/grid/mod.rs (52%) rename src/core/src/{ => renderable}/grid/parallel.rs (100%) diff --git a/src/core/src/app.rs b/src/core/src/app.rs index a3db425c..a3b19d43 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -2,7 +2,6 @@ use crate::{ //async_task::{BuildCatalogIndex, ParseTableTask, TaskExecutor, TaskResult, TaskType}, camera::CameraViewPort, downloader::Downloader, - grid::ProjetedGrid, healpix::coverage::HEALPixCoverage, inertia::Inertia, math::{ @@ -10,6 +9,7 @@ use crate::{ angle::{Angle, ArcDeg}, lonlat::{LonLat, LonLatT}, }, + renderable::grid::ProjetedGrid, renderable::Layers, renderable::{ catalog::Manager, line::RasterizedLineRenderer, moc::MOCRenderer, ImageCfg, Renderer, @@ -166,7 +166,7 @@ impl App { let manager = Manager::new(&gl, &mut shaders, &camera, &resources)?; // Grid definition - let grid = ProjetedGrid::new(aladin_div)?; + let grid = ProjetedGrid::new(gl.clone(), aladin_div)?; // Variable storing the location to move to let inertia = None; @@ -972,7 +972,7 @@ impl App { //})?; self.grid - .draw(&self.camera, &self.projection, &mut self.line_renderer)?; + .draw(&self.camera, &self.projection, &mut self.shaders)?; self.line_renderer.end(); self.line_renderer .draw(&mut self.shaders, &self.camera, &self.projection)?; diff --git a/src/core/src/image/fits.rs b/src/core/src/image/fits.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/core/src/image/jpg.rs b/src/core/src/image/jpg.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/core/src/image/mod.rs b/src/core/src/image/mod.rs deleted file mode 100644 index 264175fd..00000000 --- a/src/core/src/image/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fits; -pub mod jpg; \ No newline at end of file diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index db3b2fa7..4418587f 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -90,7 +90,6 @@ mod shaders; mod coosys; mod downloader; mod fifo_cache; -mod grid; mod healpix; mod inertia; pub mod math; diff --git a/src/core/src/grid/label.rs b/src/core/src/renderable/grid/label.rs similarity index 98% rename from src/core/src/grid/label.rs rename to src/core/src/renderable/grid/label.rs index b5547a6f..75804e9d 100644 --- a/src/core/src/grid/label.rs +++ b/src/core/src/renderable/grid/label.rs @@ -6,9 +6,9 @@ use crate::ProjectionType; use cgmath::InnerSpace; use cgmath::Vector3; -use crate::grid::XYScreen; use crate::math::angle::SerializeFmt; use crate::math::lonlat::LonLat; +use crate::math::projection::coo_space::XYScreen; use crate::math::TWICE_PI; use crate::math::angle::ToAngle; diff --git a/src/core/src/grid/meridian.rs b/src/core/src/renderable/grid/meridian.rs similarity index 99% rename from src/core/src/grid/meridian.rs rename to src/core/src/renderable/grid/meridian.rs index 28f69f7b..12a2a7e0 100644 --- a/src/core/src/grid/meridian.rs +++ b/src/core/src/renderable/grid/meridian.rs @@ -7,7 +7,7 @@ use core::ops::Range; use crate::math::MINUS_HALF_PI; use crate::ProjectionType; -use crate::grid::angle::SerializeFmt; +use super::angle::SerializeFmt; use crate::math::HALF_PI; pub fn get_intersecting_meridian( diff --git a/src/core/src/grid/mod.rs b/src/core/src/renderable/grid/mod.rs similarity index 52% rename from src/core/src/grid/mod.rs rename to src/core/src/renderable/grid/mod.rs index 625ec615..aca1a2a5 100644 --- a/src/core/src/grid/mod.rs +++ b/src/core/src/renderable/grid/mod.rs @@ -2,23 +2,22 @@ pub mod label; pub mod meridian; pub mod parallel; -use crate::grid::parallel::Parallel; -use crate::math::projection::coo_space::XYScreen; +use crate::shader::ShaderManager; use crate::Abort; +use al_core::VecData; +use parallel::Parallel; use crate::camera::CameraViewPort; -use crate::coo_space::CooSpace; use crate::math::angle; use crate::math::HALF_PI; -use crate::renderable::line; -use crate::renderable::line::PathVertices; -use crate::renderable::Renderer; use crate::ProjectionType; use al_api::color::ColorRGBA; - use al_api::grid::GridCfg; +use al_core::VertexArrayObject; +use al_core::WebGlContext; +use web_sys::WebGl2RenderingContext; -use crate::grid::label::Label; +use label::Label; pub struct ProjetedGrid { // Properties pub color: ColorRGBA, @@ -31,22 +30,22 @@ pub struct ProjetedGrid { text_renderer: TextRenderManager, fmt: angle::SerializeFmt, - line_style: line::Style, - + //line_style: line::Style, meridians: Vec, parallels: Vec, -} -use wasm_bindgen::JsValue; - -use crate::renderable::line::RasterizedLineRenderer; + vao: VertexArrayObject, + gl: WebGlContext, +} use crate::renderable::text::TextRenderManager; +use crate::renderable::Renderer; +use wasm_bindgen::JsValue; use web_sys::HtmlElement; use self::meridian::Meridian; impl ProjetedGrid { - pub fn new(aladin_div: &HtmlElement) -> Result { + pub fn new(gl: WebGlContext, aladin_div: &HtmlElement) -> Result { let text_renderer = TextRenderManager::new(aladin_div)?; let color = ColorRGBA { @@ -58,15 +57,44 @@ impl ProjetedGrid { let show_labels = true; let enabled = false; let label_scale = 1.0; - let line_style = line::Style::None; + //let line_style = line::Style::None; let fmt = angle::SerializeFmt::DMS; let thickness = 2.0; let meridians = Vec::new(); let parallels = Vec::new(); + let mut vao = VertexArrayObject::new(&gl); + vao.bind_for_update() + // Store the cartesian position of the center of the source in the a instanced VBO + .add_instanced_array_buffer( + "ndc_pos", + 4 * std::mem::size_of::(), + &[2, 2], + &[0, 2 * std::mem::size_of::()], + WebGl2RenderingContext::DYNAMIC_DRAW, + &[] as &[f32], + ) + .add_array_buffer( + "vertices", + 2 * std::mem::size_of::(), + &[2], + &[0], + WebGl2RenderingContext::STATIC_DRAW, + &[ + 0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32, + ] as &[f32], + ) + // Set the element buffer + .add_element_buffer( + WebGl2RenderingContext::STATIC_DRAW, + &[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16] as &[u16], + ) + // Unbind the buffer + .unbind(); + let grid = ProjetedGrid { color, - line_style, + //line_style, show_labels, enabled, label_scale, @@ -76,6 +104,9 @@ impl ProjetedGrid { meridians, parallels, fmt, + + vao, + gl, }; // Initialize the vertices & labels //grid.force_update(camera, projection, line_renderer); @@ -143,91 +174,6 @@ impl ProjetedGrid { Ok(()) } - // Update the grid whenever the camera moved - fn update( - &mut self, - camera: &CameraViewPort, - projection: &ProjectionType, - rasterizer: &mut RasterizedLineRenderer, - ) -> Result<(), JsValue> { - let fov = camera.get_field_of_view(); - let bbox = fov.get_bounding_box(); - let max_dim_px = camera.get_width().max(camera.get_height()) as f64; - let step_line_px = max_dim_px * 0.2; - - // update meridians - self.meridians = { - // Select the good step with a binary search - let step_lon_precised = - (bbox.get_lon_size() as f64) * step_line_px / (camera.get_width() as f64); - let step_lon = select_fixed_step(step_lon_precised); - - // Add meridians - let start_lon = bbox.lon_min() - (bbox.lon_min() % step_lon); - let mut stop_lon = bbox.lon_max(); - if bbox.all_lon() { - stop_lon -= 1e-3; - } - - let mut meridians = vec![]; - let mut lon = start_lon; - while lon < stop_lon { - if let Some(p) = - meridian::get_intersecting_meridian(lon, camera, projection, &self.fmt) - { - meridians.push(p); - } - lon += step_lon; - } - meridians - }; - - self.parallels = { - let step_lat_precised = - (bbox.get_lat_size() as f64) * step_line_px / (camera.get_height() as f64); - let step_lat = select_fixed_step(step_lat_precised); - - let mut start_lat = bbox.lat_min() - (bbox.lat_min() % step_lat); - if start_lat == -HALF_PI { - start_lat += step_lat; - } - let stop_lat = bbox.lat_max(); - let mut lat = start_lat; - - let mut parallels = vec![]; - while lat < stop_lat { - if let Some(p) = parallel::get_intersecting_parallel(lat, camera, projection) { - parallels.push(p); - } - lat += step_lat; - } - parallels - }; - - // update the line buffers - let paths = self - .meridians - .iter() - .map(|meridian| meridian.get_lines_vertices()) - .chain( - self.parallels - .iter() - .map(|parallel| parallel.get_lines_vertices()), - ) - .flatten() - .map(|vertices| PathVertices { vertices }); - - rasterizer.add_stroke_paths( - paths, - self.thickness, - &self.color, - &self.line_style, - CooSpace::NDC, - ); - - Ok(()) - } - pub fn draw_labels(&mut self) -> Result<(), JsValue> { if self.enabled && self.show_labels { let labels = self @@ -258,10 +204,106 @@ impl ProjetedGrid { &mut self, camera: &CameraViewPort, projection: &ProjectionType, - rasterizer: &mut RasterizedLineRenderer, + shaders: &mut ShaderManager, ) -> Result<(), JsValue> { if self.enabled { - self.update(camera, projection, rasterizer)?; + let fov = camera.get_field_of_view(); + let bbox = fov.get_bounding_box(); + let max_dim_px = camera.get_width().max(camera.get_height()) as f64; + let step_line_px = max_dim_px * 0.2; + + // update meridians + self.meridians = { + // Select the good step with a binary search + let step_lon_precised = + (bbox.get_lon_size() as f64) * step_line_px / (camera.get_width() as f64); + let step_lon = select_fixed_step(step_lon_precised); + + // Add meridians + let start_lon = bbox.lon_min() - (bbox.lon_min() % step_lon); + let mut stop_lon = bbox.lon_max(); + if bbox.all_lon() { + stop_lon -= 1e-3; + } + + let mut meridians = vec![]; + let mut lon = start_lon; + while lon < stop_lon { + if let Some(p) = + meridian::get_intersecting_meridian(lon, camera, projection, &self.fmt) + { + meridians.push(p); + } + lon += step_lon; + } + meridians + }; + + self.parallels = { + let step_lat_precised = + (bbox.get_lat_size() as f64) * step_line_px / (camera.get_height() as f64); + let step_lat = select_fixed_step(step_lat_precised); + + let mut start_lat = bbox.lat_min() - (bbox.lat_min() % step_lat); + if start_lat == -HALF_PI { + start_lat += step_lat; + } + let stop_lat = bbox.lat_max(); + let mut lat = start_lat; + + let mut parallels = vec![]; + while lat < stop_lat { + if let Some(p) = parallel::get_intersecting_parallel(lat, camera, projection) { + parallels.push(p); + } + lat += step_lat; + } + parallels + }; + + // update the line buffers + let paths = self + .meridians + .iter() + .map(|meridian| meridian.get_lines_vertices()) + .chain( + self.parallels + .iter() + .map(|parallel| parallel.get_lines_vertices()), + ) + .flatten(); + + let mut buf: Vec = vec![]; + + for vertices in paths { + let vertices = vertices.as_ref(); + let path_vertices_buf_iter = vertices + .iter() + .zip(vertices.iter().skip(1)) + .map(|(a, b)| [a[0], a[1], b[0], b[1]]) + .flatten(); + + buf.extend(path_vertices_buf_iter); + } + + self.vao.bind_for_update().update_instanced_array( + "ndc_pos", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&buf), + ); + + let num_instances = buf.len() / 4; + + crate::shader::get_shader(&self.gl, shaders, "line_inst_ndc.vert", "line_base.frag")? + .bind(&self.gl) + .attach_uniform("u_color", &self.color) + .attach_uniform("u_width", &self.thickness) + .bind_vertex_array_object_ref(&self.vao) + .draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + num_instances as i32, + ); } Ok(()) diff --git a/src/core/src/grid/parallel.rs b/src/core/src/renderable/grid/parallel.rs similarity index 100% rename from src/core/src/grid/parallel.rs rename to src/core/src/renderable/grid/parallel.rs diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index d4f7f006..d6167b66 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -213,7 +213,7 @@ impl RasterizedLineRenderer { &[2, 2], &[0, 2 * std::mem::size_of::()], WebGl2RenderingContext::DYNAMIC_DRAW, - SliceData(&[]), + &[] as &[f32], ) .add_array_buffer( "vertices", @@ -221,14 +221,14 @@ impl RasterizedLineRenderer { &[2], &[0], WebGl2RenderingContext::STATIC_DRAW, - SliceData(&[ + &[ 0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32, - ]), + ] as &[f32], ) // Set the element buffer .add_element_buffer( WebGl2RenderingContext::STATIC_DRAW, - SliceData(&[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16]), + &[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16] as &[u16], ) // Unbind the buffer .unbind(); diff --git a/src/core/src/renderable/mod.rs b/src/core/src/renderable/mod.rs index d76c16b2..b778be3d 100644 --- a/src/core/src/renderable/mod.rs +++ b/src/core/src/renderable/mod.rs @@ -1,5 +1,6 @@ pub mod catalog; pub mod final_pass; +pub mod grid; pub mod hips; pub mod image; pub mod line; diff --git a/src/js/View.js b/src/js/View.js index 6993faa7..a9908534 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -1738,8 +1738,11 @@ export let View = (function () { if (noMoreLayersToWaitFor) { if (self.empty) { - // no promises to launch! - //self.aladin.setBaseImageLayer(self.aladin.createImageSurvey(ImageHiPS.DEFAULT_SURVEY_ID)); + // no promises to launch and the view has no HiPS. + // This situation can occurs if the MOCServer is out + // If so we can directly put the url of the DSS hosted in alasky, + // it the best I can do if the MOCServer is out + self.aladin.setBaseImageLayer("https://alaskybis.cds.unistra.fr/DSS/DSSColor/"); } else { // there is surveys that have been queried // rename the first overlay layer to "base" From 3fee4a345d8a198a29b2e34d74fa3546599fd99d Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Wed, 26 Jun 2024 15:46:25 +0200 Subject: [PATCH 08/12] propose a removeHiPSFromFavorites method on the aladin object. Targets issue: https://github.com/cds-astro/aladin-lite/issues/171 --- examples/al-save-colormap.html | 2 ++ src/js/Aladin.js | 44 +++++++++++++++++++++++++++++++++- src/js/DefaultHiPSCache.js | 4 ++++ src/js/ImageFITS.js | 4 +++- src/js/ImageHiPS.js | 16 +++++++------ src/js/View.js | 37 ++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 9 deletions(-) diff --git a/examples/al-save-colormap.html b/examples/al-save-colormap.html index 6451864f..f12ca75d 100644 --- a/examples/al-save-colormap.html +++ b/examples/al-save-colormap.html @@ -25,6 +25,8 @@ survey3.setColormap('cubehelix', {stretch: 'asinh'}); aladin.setImageLayer(survey2); + + aladin.removeHiPSFromFavorites(survey3); }); diff --git a/src/js/Aladin.js b/src/js/Aladin.js index 1ab3ccc4..b9053b62 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -1578,6 +1578,49 @@ export let Aladin = (function () { */ Aladin.createImageSurvey = Aladin.prototype.createImageSurvey; + /** + * Remove a HiPS/FITS image from the list of favorites. + * + * @throws A warning when the asset is currently present in the view + * + * @memberof Aladin + * @param {string|ImageHiPS|ImageFITS} urlOrHiPSOrFITS - Can be: + *

    + *
  • 1. An url that refers to a HiPS
  • + *
  • 2. Or it can be a CDS identifier that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
  • + *
  • 3. A {@link ImageHiPS} HiPS object created from {@link A.imageHiPS}
  • + *
  • 4. A {@link ImageFITS} FITS image object
  • + *
+ */ + Aladin.prototype.removeHiPSFromFavorites = function (survey) { + if (this.contains(survey)) { + // TODO: handle this case + console.warn(survey + ' is among the list of HiPS currently in the view.'); + } + + if (typeof survey !== "string") { + survey = survey.id; + } + + HiPSCache.delete(survey); + } + + /** + * Check whether a survey is currently in the view + * + * @memberof Aladin + * @param {string|ImageHiPS|ImageFITS} urlOrHiPSOrFITS - Can be: + *
    + *
  • 1. An url that refers to a HiPS
  • + *
  • 2. Or it can be a CDS identifier that refers to a HiPS. One can found the list of IDs {@link https://aladin.cds.unistra.fr/hips/list| here}
  • + *
  • 3. A {@link ImageHiPS} HiPS object created from {@link A.imageHiPS}
  • + *
  • 4. A {@link ImageFITS} FITS image object
  • + *
+ */ + Aladin.prototype.contains = function(survey) { + this.view.contains(survey) + } + /** * Creates a FITS image object * @deprecated prefer use {@link A.imageFITS} @@ -2011,7 +2054,6 @@ aladin.on("positionChanged", ({ra, dec}) => { } } objects = Object.values(objListPerCatalog); - console.log(objects); this.view.selectObjects(objects); }; diff --git a/src/js/DefaultHiPSCache.js b/src/js/DefaultHiPSCache.js index 5fb345b3..449f051e 100644 --- a/src/js/DefaultHiPSCache.js +++ b/src/js/DefaultHiPSCache.js @@ -46,6 +46,10 @@ export let HiPSCache = (function () { return HiPSCache.cache[key]; }; + HiPSCache.contains = function (key) { + return HiPSCache.cache[key] !== undefined && HiPSCache.cache[key] !== null; + }; + // A cache storing directly surveys important information to not query for the properties each time HiPSCache.cache = {}; diff --git a/src/js/ImageFITS.js b/src/js/ImageFITS.js index da1ef0dd..951a335e 100644 --- a/src/js/ImageFITS.js +++ b/src/js/ImageFITS.js @@ -87,7 +87,9 @@ export let ImageFITS = (function () { } ImageFITS.prototype._saveInCache = function () { - HiPSCache.append(this.id, this); + if (HiPSCache.contains(self.id)) { + HiPSCache.append(this.id, this); + } }; // A cache storing directly the images to not query for the properties each time diff --git a/src/js/ImageHiPS.js b/src/js/ImageHiPS.js index 1fae1360..7261c703 100644 --- a/src/js/ImageHiPS.js +++ b/src/js/ImageHiPS.js @@ -477,13 +477,15 @@ export let ImageHiPS = (function () { surveyOpt.numBitsPerPixel = self.numBitsPerPixel; } - HiPSCache.append(self.id, { - // Erase by the cache already put values which is considered - // as the ground truth - ...HiPSCache.get[self.id], - // append new important infos from the properties queried - ...surveyOpt, - }); + if (HiPSCache.contains(self.id)) { + HiPSCache.append(self.id, { + // Erase by the cache already put values which is considered + // as the ground truth + ...HiPSCache.get[self.id], + // append new important infos from the properties queried + ...surveyOpt, + }); + } }; /** diff --git a/src/js/View.js b/src/js/View.js index a9908534..366208f1 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -1662,6 +1662,7 @@ export let View = (function () { } imageLayer.added = true; + this.imageLayers.set(layerName, imageLayer); // select the layer if he is on top @@ -1836,6 +1837,42 @@ export let View = (function () { } }; + View.prototype.contains = function(survey) { + if (survey instanceof ImageHiPS || survey instanceof ImageFITS) { + if (survey.added === true) { + return true; + } + + // maybe it has not been added yet + let found = this.imageLayersBeingQueried + .values() + .some((s) => { + return s === survey; + }); + + return found; + } + + // Case where survey is a string + if(this.imageLayers + .values() + .some((s) => { + return s.id === survey; + })) { + return true; + } + + if(this.imageLayersBeingQueried + .values() + .some((s) => { + return s.id === survey; + })) { + return true; + } + + return false; + } + View.prototype.setHiPSUrl = function (pastUrl, newUrl) { try { this.wasm.setHiPSUrl(pastUrl, newUrl); From 631b2cdf4b5ef7ee07b7ce8a7443a4827c63dcaa Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Mon, 1 Jul 2024 09:41:49 +0200 Subject: [PATCH 09/12] WIP: polyline catalog renderer --- examples/al-init-custom-options.html | 3 +- src/core/Cargo.toml | 2 +- src/core/src/lib.rs | 7 +- src/core/src/math/angle.rs | 4 +- src/core/src/math/lonlat.rs | 5 +- src/core/src/renderable/line/mod.rs | 32 +--- src/core/src/renderable/moc/renderer.rs | 137 -------------- src/core/src/renderable/mod.rs | 1 + src/core/src/renderable/shape/box.rs | 1 + src/core/src/renderable/shape/circle.rs | 0 src/core/src/renderable/shape/ellipsis.rs | 0 src/core/src/renderable/shape/image.rs | 0 src/core/src/renderable/shape/mod.rs | 62 +++++++ src/core/src/renderable/shape/polyline.rs | 210 ++++++++++++++++++++++ src/js/Aladin.js | 2 + src/js/View.js | 2 + 16 files changed, 289 insertions(+), 179 deletions(-) create mode 100644 src/core/src/renderable/shape/box.rs create mode 100644 src/core/src/renderable/shape/circle.rs create mode 100644 src/core/src/renderable/shape/ellipsis.rs create mode 100644 src/core/src/renderable/shape/image.rs create mode 100644 src/core/src/renderable/shape/mod.rs create mode 100644 src/core/src/renderable/shape/polyline.rs diff --git a/examples/al-init-custom-options.html b/examples/al-init-custom-options.html index 1dc96761..8e093010 100644 --- a/examples/al-init-custom-options.html +++ b/examples/al-init-custom-options.html @@ -7,10 +7,9 @@
- + \ No newline at end of file diff --git a/src/core/src/app.rs b/src/core/src/app.rs index a3b19d43..f8ebae5a 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -52,7 +52,7 @@ pub struct App { //ui: GuiRef, shaders: ShaderManager, - camera: CameraViewPort, + pub camera: CameraViewPort, downloader: Downloader, tile_fetcher: TileFetcherQueue, @@ -94,7 +94,7 @@ pub struct App { colormaps: Colormaps, - projection: ProjectionType, + pub projection: ProjectionType, // Async data receivers fits_send: async_channel::Sender, @@ -849,16 +849,6 @@ impl App { Ok(has_camera_moved) } - pub(crate) fn reset_north_orientation(&mut self) { - // Reset the rotation around the center if there is one - self.camera - .set_rotation_around_center(Angle(0.0), &self.projection); - // Reset the camera position to its current position - // this will keep the current position but reset the orientation - // so that the north pole is at the top of the center. - self.set_center(&self.get_center()); - } - pub(crate) fn read_pixel(&self, pos: &Vector2, layer: &str) -> Result { if let Some(lonlat) = self.screen_to_world(pos) { if let Some(survey) = self.layers.get_hips_from_layer(layer) { @@ -1405,10 +1395,10 @@ impl App { pub(crate) fn world_to_screen(&self, ra: f64, dec: f64) -> Option> { let lonlat = LonLatT::new(ArcDeg(ra).into(), ArcDeg(dec).into()); - let model_pos_xyz = lonlat.vector(); + let icrs_pos = lonlat.vector(); self.projection - .view_to_screen_space(&model_pos_xyz, &self.camera) + .icrs_celestial_to_screen_space(&icrs_pos, &self.camera) } pub(crate) fn screen_to_world(&self, pos: &Vector2) -> Option> { @@ -1439,11 +1429,11 @@ impl App { LonLatT::new(ra, dec) } + /// lonlat must be given in icrs frame pub(crate) fn set_center(&mut self, lonlat: &LonLatT) { self.prev_cam_position = self.camera.get_center().truncate(); - self.camera - .set_center(lonlat, CooSystem::ICRS, &self.projection); + self.camera.set_center(lonlat, &self.projection); self.request_for_new_tiles = true; // And stop the current inertia as well if there is one @@ -1534,17 +1524,17 @@ impl App { self.inertia = Some(Inertia::new(ampl.to_radians(), axis)) } - pub(crate) fn rotate_around_center(&mut self, theta: ArcDeg) { + pub(crate) fn set_view_center_pos_angle(&mut self, theta: ArcDeg) { self.camera - .set_rotation_around_center(theta.into(), &self.projection); + .set_view_center_pos_angle(theta.into(), &self.projection); // New tiles can be needed and some tiles can be removed self.request_for_new_tiles = true; self.request_redraw = true; } - pub(crate) fn get_rotation_around_center(&self) -> &Angle { - self.camera.get_rotation_around_center() + pub(crate) fn get_north_shift_angle(&self) -> Angle { + self.camera.get_north_shift_angle() } pub(crate) fn set_fov(&mut self, fov: Angle) { diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs index 27d0a7e9..e1356ecc 100644 --- a/src/core/src/camera/viewport.rs +++ b/src/core/src/camera/viewport.rs @@ -17,14 +17,16 @@ use crate::healpix::coverage::HEALPixCoverage; use crate::math::angle::ToAngle; use crate::math::{projection::coo_space::XYZWModel, projection::domain::sdf::ProjDef}; +use al_core::log::console_log; use cgmath::{Matrix4, Vector2}; pub struct CameraViewPort { // The field of view angle aperture: Angle, - center: Vector4, // The rotation of the camera rotation_center_angle: Angle, + center: Vector4, w2m_rot: Rotation, + center_rot: Angle, w2m: Matrix4, m2w: Matrix4, @@ -74,6 +76,7 @@ pub struct CameraViewPort { } use al_api::coo_system::CooSystem; use al_core::WebGlContext; +use js_sys::Math::atan2; use crate::{ coosys, @@ -101,8 +104,8 @@ impl CameraViewPort { let w2m = Matrix4::identity(); let m2w = w2m; - let center = Vector4::new(0.0, 0.0, 1.0, 1.0); - + let center_rot = Angle(0.0); + let center = Vector4::new(0.0, 0.0, 0.0, 1.0); let moved = false; let zoomed = false; @@ -122,9 +125,6 @@ impl CameraViewPort { let width = width * dpi; let height = height * dpi; - //let dpi = 1.0; - //gl.scissor(0, 0, width as i32, height as i32); - let aspect = height / width; let ndc_to_clip = Vector2::new(1.0, (height as f64) / (width as f64)); let clip_zoom_factor = 1.0; @@ -143,6 +143,7 @@ impl CameraViewPort { CameraViewPort { // The field of view angle aperture, + center_rot, center, // The rotation of the cameraq w2m_rot, @@ -477,10 +478,11 @@ impl CameraViewPort { self.update_rot_matrices(proj); } - pub fn set_center(&mut self, lonlat: &LonLatT, coo_sys: CooSystem, proj: &ProjectionType) { + /// lonlat must be given in icrs frame + pub fn set_center(&mut self, lonlat: &LonLatT, proj: &ProjectionType) { let icrs_pos: Vector4<_> = lonlat.vector(); - let view_pos = coosys::apply_coo_system(coo_sys, self.get_coo_system(), &icrs_pos); + let view_pos = CooSystem::ICRS.to(self.get_coo_system()) * icrs_pos; let rot = Rotation::from_sky_position(&view_pos); // Apply the rotation to the camera to go @@ -527,13 +529,8 @@ impl CameraViewPort { if self.reversed_longitude != reversed_longitude { self.reversed_longitude = reversed_longitude; - self.rotation_center_angle = -self.rotation_center_angle; self.update_rot_matrices(proj); } - - // The camera is reversed => it has moved - self.moved = true; - self.time_last_move = Time::now(); } pub fn get_longitude_reversed(&self) -> bool { @@ -599,14 +596,17 @@ impl CameraViewPort { self.zoomed = false; } + #[inline] pub fn get_aperture(&self) -> Angle { self.aperture } + #[inline] pub fn get_center(&self) -> &Vector4 { &self.center } + #[inline] pub fn is_allsky(&self) -> bool { self.is_allsky } @@ -619,13 +619,14 @@ impl CameraViewPort { self.coo_sys } - pub fn set_rotation_around_center(&mut self, theta: Angle, proj: &ProjectionType) { - self.rotation_center_angle = theta; + pub fn set_view_center_pos_angle(&mut self, phi: Angle, proj: &ProjectionType) { + self.center_rot = phi; + self.update_rot_matrices(proj); } - pub fn get_rotation_around_center(&self) -> &Angle { - &self.rotation_center_angle + pub fn get_north_shift_angle(&self) -> Angle { + (self.w2m.x.y).atan2(self.w2m.y.y).to_angle() } } use crate::ProjectionType; @@ -657,16 +658,14 @@ impl CameraViewPort { } fn update_center(&mut self) { - // The center position is on the 3rd column of the w2m matrix self.center = self.w2m.z; - - let axis = &self.center.truncate(); - let center_rot = Rotation::from_axis_angle(axis, self.rotation_center_angle); - + // The center position is on the 3rd column of the w2m matrix + let center_axis = &self.center.truncate(); // Re-update the model matrix to take into account the rotation // by theta around the center axis - let final_rot = center_rot * self.w2m_rot; - self.w2m = (&final_rot).into(); + let r = Rotation::from_axis_angle(center_axis, self.center_rot) * self.w2m_rot; + + self.w2m = (&r).into(); if self.reversed_longitude { self.w2m = self.w2m * ID_R; } diff --git a/src/core/src/lib.rs b/src/core/src/lib.rs index 4c0a3ef1..959d168e 100644 --- a/src/core/src/lib.rs +++ b/src/core/src/lib.rs @@ -494,20 +494,30 @@ impl WebClient { /// # Arguments /// /// * `theta` - The rotation angle in degrees - #[wasm_bindgen(js_name = setRotationAroundCenter)] - pub fn rotate_around_center(&mut self, theta: f64) -> Result<(), JsValue> { + #[wasm_bindgen(js_name = setViewCenterPosAngle)] + pub fn set_view_center_pos_angle(&mut self, theta: f64) -> Result<(), JsValue> { let theta = ArcDeg(theta); - self.app.rotate_around_center(theta); + self.app.set_view_center_pos_angle(theta); Ok(()) } /// Get the absolute orientation angle of the view - #[wasm_bindgen(js_name = getRotationAroundCenter)] - pub fn get_rotation_around_center(&mut self) -> Result { - let theta = self.app.get_rotation_around_center(); + #[wasm_bindgen(js_name = getViewCenterFromNorthPoleAngle)] + pub fn get_north_shift_angle(&mut self) -> Result { + let phi = self.app.get_north_shift_angle(); + Ok(phi.to_degrees()) + } + + #[wasm_bindgen(js_name = getNorthPoleCelestialPosition)] + pub fn get_north_pole_celestial_position(&mut self) -> Result, JsValue> { + let np = self + .app + .projection + .north_pole_celestial_space(&self.app.camera); - Ok(theta.0 * 360.0 / (2.0 * std::f64::consts::PI)) + let (lon, lat) = (np.lon().to_degrees(), np.lat().to_degrees()); + Ok(Box::new([lon, lat])) } /// Get if the longitude axis is reversed @@ -571,12 +581,6 @@ impl WebClient { Ok(Box::new([lon_deg.0, lat_deg.0])) } - /// Rest the north pole orientation to the top of the screen - #[wasm_bindgen(js_name = resetNorthOrientation)] - pub fn reset_north_orientation(&mut self) { - self.app.reset_north_orientation(); - } - /// Go from a location to another one /// /// # Arguments diff --git a/src/core/src/math/projection/mod.rs b/src/core/src/math/projection/mod.rs index 559fd93a..a64eae80 100644 --- a/src/core/src/math/projection/mod.rs +++ b/src/core/src/math/projection/mod.rs @@ -150,7 +150,16 @@ pub enum ProjectionType { //Hpx(mapproj::hybrid::hpx::Hpx), } +use crate::math::lonlat::LonLat; impl ProjectionType { + pub fn north_pole_celestial_space(&self, camera: &CameraViewPort) -> LonLatT { + // This is always defined + let np_world = self.north_pole_world_space(); + + let np_celestial = camera.get_w2m() * np_world; + np_celestial.lonlat() + } + /// Screen to model space deprojection /// Perform a screen to the world space deprojection @@ -209,41 +218,28 @@ impl ProjectionType { self.world_to_screen_space(&pos_world_space, camera) } - pub fn view_to_screen_space( + pub fn icrs_celestial_to_screen_space( &self, - pos_model_space: &XYZWModel, + icrs_celestial_pos: &XYZWModel, camera: &CameraViewPort, ) -> Option> { - self.view_to_normalized_device_space(pos_model_space, camera) + self.icrs_celestial_to_normalized_device_space(icrs_celestial_pos, camera) .map(|ndc_pos| crate::ndc_to_screen_space(&ndc_pos, camera)) } - pub fn view_to_normalized_device_space( + pub fn icrs_celestial_to_normalized_device_space( &self, - pos_model_space: &XYZWModel, + icrs_celestial_pos: &XYZWModel, camera: &CameraViewPort, ) -> Option> { let view_coosys = camera.get_coo_system(); let c = CooSystem::ICRS.to::(view_coosys); let m2w = camera.get_m2w(); - let pos_world_space = m2w * c * pos_model_space; + let pos_world_space = m2w * c * icrs_celestial_pos; self.world_to_normalized_device_space(&pos_world_space, camera) } - /*pub fn view_to_normalized_device_space_unchecked( - &self, - pos_view_space: &Vector4, - camera: &CameraViewPort, - ) -> Vector2 { - let view_coosys = camera.get_coo_system(); - let c = CooSystem::ICRS.to::(view_coosys); - - let m2w = camera.get_m2w(); - let pos_world_space = m2w * c * pos_view_space; - self.world_to_normalized_device_space_unchecked(&pos_world_space, camera) - }*/ - pub fn model_to_normalized_device_space( &self, pos_model_space: &XYZWModel, @@ -673,6 +669,21 @@ pub trait Projection { /// /// * ``pos_world_space`` - The position in the world space fn world_to_clip_space(&self, pos_world_space: &XYZWWorld) -> Option>; + + /// (`alpha_p`, `delta_p`) in the WCS II paper from Mark Calabretta. + #[inline] + fn north_pole_world_space(&self) -> XYZWWorld { + // This is always defined + self.clip_to_world_space(&XYClip::new(0.0, 1.0 - 1e-5)) + .unwrap() + } + + #[inline] + fn south_pole_world_space(&self) -> XYZWWorld { + // This is always defined + self.clip_to_world_space(&XYClip::new(0.0, -1.0 + 1e-5)) + .unwrap() + } } use mapproj::ProjXY; @@ -680,6 +691,8 @@ use mapproj::ProjXY; use self::coo_space::XYScreen; use self::coo_space::XYNDC; +use super::lonlat::LonLatT; + impl<'a, P> Projection for &'a P where P: CanonicalProjection, diff --git a/src/core/src/math/rotation.rs b/src/core/src/math/rotation.rs index d20e4690..137d4747 100644 --- a/src/core/src/math/rotation.rs +++ b/src/core/src/math/rotation.rs @@ -1,7 +1,8 @@ use crate::math; -use cgmath::Quaternion; use cgmath::{BaseFloat, InnerSpace}; +use cgmath::{Euler, Quaternion}; use cgmath::{Vector3, Vector4}; +use core::f64::consts::PI; #[derive(Clone, Copy, Debug)] // Internal structure of a rotation, a quaternion @@ -136,6 +137,31 @@ where m2w * pos_model_space } + + pub fn euler(&self) -> Euler> { + self.0.into() + } + + /// Extract the 3 euler angles from the quaternion + /// Aladin Lite rotation basis is formed by Z, X, Y axis: + /// * Z axis is pointing towards us + /// * Y is pointing upward + /// * X is defined from the right-hand rule to form a basis + /// + /// The first euler angle describes the longitude (rotation around the Y axis) <=> pitch + /// The second euler angle describes the latitude (rotation around the X' modified axis) <=> yaw + /// The third euler angle describes a rotation deviation from the north pole (rotation around the Z'' modified axis) <=> roll + /// + /// Equations come from this paper (Appendix 6): + /// https://ntrs.nasa.gov/api/citations/19770024290/downloads/19770024290.pdf + pub fn euler_YXZ(&self) -> (Angle, Angle, Angle) { + let m: Matrix4 = self.0.into(); + + let a = m.x.z.atan2(m.z.z); + let b = (-m.z.y).atan2((S::one() - m.z.y * m.z.y).sqrt()); + let c = m.x.y.atan2(m.y.y); + (Angle(a), Angle(b), Angle(c)) + } } use std::ops::Mul; diff --git a/src/core/src/renderable/hips/mod.rs b/src/core/src/renderable/hips/mod.rs index 8f042e95..db2d1797 100644 --- a/src/core/src/renderable/hips/mod.rs +++ b/src/core/src/renderable/hips/mod.rs @@ -58,7 +58,7 @@ fn is_too_large(cell: &HEALPixCell, camera: &CameraViewPort, projection: &Projec .iter() .filter_map(|(lon, lat)| { let vertex = crate::math::lonlat::radec_to_xyzw(Angle(*lon), Angle(*lat)); - projection.view_to_screen_space(&vertex, camera) + projection.icrs_celestial_to_screen_space(&vertex, camera) }) .collect::>(); diff --git a/src/js/Aladin.js b/src/js/Aladin.js index 6edb986e..16cd6312 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -1867,8 +1867,26 @@ export let Aladin = (function () { this.view.decreaseZoom(0.01); }; - Aladin.prototype.setRotation = function (rotation) { - this.view.setRotation(rotation); + /** + * Set the view center rotation in degrees + * + * @memberof Aladin + * @param {number} rotation - The center rotation in degrees. Positive angles rotates the + * view in the counter clockwise order (or towards the east) + */ + Aladin.prototype.setViewCenterPosAngle = function (rotation) { + this.view.setViewCenterPosAngle(rotation); + }; + + /** + * Get the view center to north pole angle in degrees. This is equivalent to getting the 3rd Euler angle + * + * @memberof Aladin + * + * @returns {number} - Angle between the position center and the north pole + */ + Aladin.prototype.getCenter2NorthPoleAngle = function () { + return this.view.wasm.getViewCenterFromNorthPoleAngle(); }; // @api @@ -2264,9 +2282,8 @@ aladin.on("positionChanged", ({ra, dec}) => { * Return the current view WCS as a key-value dictionary * Can be useful in coordination with getViewDataURL * - * NOTE + TODO : Rotations are not implemented yet - * - * @API + * @memberof Aladin + * @returns {Object} - A JS object describing the WCS of the view. */ Aladin.prototype.getViewWCS = function () { // get general view properties @@ -2276,11 +2293,11 @@ aladin.on("positionChanged", ({ra, dec}) => { const height = this.view.height; // get values common for all - let cdelt1 = fov[0] / width; + let cdelt1 = -fov[0] / width; const cdelt2 = fov[1] / height; - const projectionName = this.getProjectionName(); + const projName = this.getProjectionName(); - if (projectionName == "FEYE") + if (projName == "FEYE") return "Fish eye projection is not supported by WCS standards."; // reversed longitude case @@ -2339,8 +2356,8 @@ aladin.on("positionChanged", ({ra, dec}) => { CRPIX2: height / 2 + 0.5, CRVAL1: center[0], CRVAL2: center[1], - CTYPE1: cooType1 + projectionName, - CTYPE2: cooType2 + projectionName, + CTYPE1: cooType1 + projName, + CTYPE2: cooType2 + projName, CUNIT1: "deg ", CUNIT2: "deg ", CDELT1: cdelt1, @@ -2351,6 +2368,48 @@ aladin.on("positionChanged", ({ra, dec}) => { // the radecsys keyword if (radesys == "ICRS ") WCS.RADESYS = radesys; + const isProjZenithal = ['TAN', 'SIN', 'STG', 'ZEA'].some((p) => p === projName) + if (isProjZenithal) { + // zenithal projections + // express the 3rd euler angle for zenithal projection + let thirdEulerAngle = this.getCenter2NorthPoleAngle(); + WCS.LONPOLE = 180 - thirdEulerAngle + } else { + // cylindrical or pseudo-cylindrical projections + if (!radesys) { + console.warn('TODO: Galactic frame 3rd euler rotation not handled for cylindrical projections') + } else if (WCS.CRVAL2 === 0) { + // ref point on the equator not handled (yet) + console.warn('TODO: 3rd euler rotation is not handled for ref point located at delta_0 = 0') + } else { + // ref point not on the equator + const npLonlat = this.view.wasm.getNorthPoleCelestialPosition(); + let dLon = WCS.CRVAL1 - npLonlat[0]; + + // dlon angle must lie between -PI and PI + // For dlon angle between -PI;-PI/2 or PI/2;PI one must invert LATPOLE + if (dLon < -90 || dLon > 90) { + // so that the south pole becomes upward to the ref point + WCS.LATPOLE = -90 + } + + const toRad = Math.PI / 180 + const toDeg = 1.0 / toRad; + + // Reverse the Eq 9 from the WCS II paper from Mark Calabretta to obtain LONPOLE + // function of CRVAL2 and native coordinates of the fiducial ref point, i.e. (phi_0, theta_0) = (0, 0) + // for cylindrical projections + WCS.LONPOLE = Math.asin(Math.sin(dLon * toRad) * Math.cos(WCS.CRVAL2 * toRad)) * toDeg; + + if (WCS.CRVAL2 < 0) { + // ref point is located in the south hemisphere + WCS.LONPOLE = -180 - WCS.LONPOLE; + } + + console.log("euler rot ?:", 180 - WCS.LONPOLE) + } + } + return WCS; }; diff --git a/src/js/View.js b/src/js/View.js index 09b5a411..7139180a 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -546,6 +546,8 @@ export let View = (function () { try { const [lon, lat] = view.aladin.pix2world(xymouse.x, xymouse.y, 'icrs'); view.pointTo(lon, lat); + // reset the rotation around center view + view.setViewCenterPosAngle(0.0); } catch (err) { return; @@ -709,7 +711,7 @@ export let View = (function () { view.pinchZoomParameters.initialFov = fov; view.pinchZoomParameters.initialDistance = Math.sqrt(Math.pow(e.targetTouches[0].clientX - e.targetTouches[1].clientX, 2) + Math.pow(e.targetTouches[0].clientY - e.targetTouches[1].clientY, 2)); - view.fingersRotationParameters.initialViewAngleFromCenter = view.wasm.getRotationAroundCenter(); + view.fingersRotationParameters.initialViewAngleFromCenter = view.wasm.getNorthShiftAngle(); view.fingersRotationParameters.initialFingerAngle = Math.atan2(e.targetTouches[1].clientY - e.targetTouches[0].clientY, e.targetTouches[1].clientX - e.targetTouches[0].clientX) * 180.0 / Math.PI; return; @@ -973,7 +975,7 @@ export let View = (function () { // planetary survey case rotation -= fingerAngleDiff; } - view.wasm.setRotationAroundCenter(rotation); + view.setViewCenterPosAngle(rotation); } // zoom @@ -1577,8 +1579,8 @@ export let View = (function () { }); } - View.prototype.setRotation = function(rotation) { - this.wasm.setRotationAroundCenter(rotation); + View.prototype.setViewCenterPosAngle = function(rotation) { + this.wasm.setViewCenterPosAngle(rotation); } View.prototype.setGridOptions = function (options) { From 253c272262ae310f8a2383ca74f2794dc98d90f2 Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 2 Jul 2024 18:55:38 +0200 Subject: [PATCH 11/12] remove some rust warnings --- src/core/src/camera/viewport.rs | 5 ----- src/core/src/math/rotation.rs | 3 +-- src/core/src/renderable/shape/mod.rs | 4 ++-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/core/src/camera/viewport.rs b/src/core/src/camera/viewport.rs index e1356ecc..f8c19879 100644 --- a/src/core/src/camera/viewport.rs +++ b/src/core/src/camera/viewport.rs @@ -17,13 +17,11 @@ use crate::healpix::coverage::HEALPixCoverage; use crate::math::angle::ToAngle; use crate::math::{projection::coo_space::XYZWModel, projection::domain::sdf::ProjDef}; -use al_core::log::console_log; use cgmath::{Matrix4, Vector2}; pub struct CameraViewPort { // The field of view angle aperture: Angle, // The rotation of the camera - rotation_center_angle: Angle, center: Vector4, w2m_rot: Rotation, center_rot: Angle, @@ -76,7 +74,6 @@ pub struct CameraViewPort { } use al_api::coo_system::CooSystem; use al_core::WebGlContext; -use js_sys::Math::atan2; use crate::{ coosys, @@ -134,7 +131,6 @@ impl CameraViewPort { let is_allsky = true; let time_last_move = Time::now(); - let rotation_center_angle = Angle(0.0); let reversed_longitude = false; let texture_depth = 0; @@ -151,7 +147,6 @@ impl CameraViewPort { m2w, dpi, - rotation_center_angle, // The width over height ratio aspect, // The width of the screen in pixels diff --git a/src/core/src/math/rotation.rs b/src/core/src/math/rotation.rs index 137d4747..d66d9c96 100644 --- a/src/core/src/math/rotation.rs +++ b/src/core/src/math/rotation.rs @@ -2,7 +2,6 @@ use crate::math; use cgmath::{BaseFloat, InnerSpace}; use cgmath::{Euler, Quaternion}; use cgmath::{Vector3, Vector4}; -use core::f64::consts::PI; #[derive(Clone, Copy, Debug)] // Internal structure of a rotation, a quaternion @@ -154,7 +153,7 @@ where /// /// Equations come from this paper (Appendix 6): /// https://ntrs.nasa.gov/api/citations/19770024290/downloads/19770024290.pdf - pub fn euler_YXZ(&self) -> (Angle, Angle, Angle) { + pub fn euler_yxz(&self) -> (Angle, Angle, Angle) { let m: Matrix4 = self.0.into(); let a = m.x.z.atan2(m.z.z); diff --git a/src/core/src/renderable/shape/mod.rs b/src/core/src/renderable/shape/mod.rs index 41cee56e..6c9fc140 100644 --- a/src/core/src/renderable/shape/mod.rs +++ b/src/core/src/renderable/shape/mod.rs @@ -50,7 +50,7 @@ pub enum Style { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -struct Footprint { +pub struct Footprint { shapes: Vec, /// Some styling meta data color: ColorRGBA, @@ -59,4 +59,4 @@ struct Footprint { style: Style, } -type Catalog = Footprint; +pub type Catalog = Footprint; From e89769c87db2f459c3a519cd6a0f5d09d09daa8f Mon Sep 17 00:00:00 2001 From: Matthieu Baumann Date: Tue, 2 Jul 2024 18:57:51 +0200 Subject: [PATCH 12/12] update changelog for v3.4.2-beta --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc64d0bb..d2490b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,11 @@ # Changelogs -## Unreleased +## 3.4.2-beta * [impr] Improve `WCS` view export with 3rd euler rotation encoding: . Still some cases are to be handled like: crval on the equator or cylindrical with a galactic frame rotation. * [fixed] Change `RADECSYS` to `RADESYS` for `Aladin#getViewWCS` to follow fits standard deprecation * [feat] Add new method `Aladin#getViewImageBuffer` to get the current view as a PNG buffer -* [feat] New line rasterizer using GL instancing. +* [feat] New line rasterizer using GL instancing. This enhances the rendering speed of MOCs. ## 3.3.3